Skip to content

Instantly share code, notes, and snippets.

@HarrisonGrodin
Last active October 21, 2021 22:38
Show Gist options
  • Save HarrisonGrodin/c70a2efec9ac047c78b7b5fb88bd6e37 to your computer and use it in GitHub Desktop.
Save HarrisonGrodin/c70a2efec9ac047c78b7b5fb88bd6e37 to your computer and use it in GitHub Desktop.
Standard ML style guide

Standard ML Style Guide

Core Language

atexp

Special Constant: <scon>

<scon>

Value Identifier: ⟨op⟩<longvid>

<longvid>
op<longvid>

❓ Is this the best style for infix operators? Other ideas would be:

  • op <longvid>, but looks odd in curried scenarios (e.g., List.foldr op + 0 vs List.foldr x + 0)
  • (op <longvid>), except (op * )

Record: { <exprows...> }

{}
{ <lab> = <exp> }
{ <lab1> = <exp1>, …, <labn> = <expn> }

❓ Should the spacing be required next to the braces? Alternative would be {<lab1> = <exp1>, …, <labn> = <expn>}.

{ <lab1> = <exp1>
, …
, <labn> = <expn>
}
⚠️ Style Errors
  • Using {} over () at type unit (rather than type {})?

Record Selector: #lab

#lab

0-tuple: ()

()
⚠️ Style Errors
  • Using () over {} at type {} (rather than type unit)?

n-tuple: (<exp1>, …, <expn>)

(<exp1>, …, <expn>)
( <exp1>
, …
, <expn>
)

❓ Spaces probably shouldn't be used next the parentheses. Does that influence the decision for records?

List: [<exp1>, …, <expn>]

[]
[<exp1>]
[<exp1>, …, <expn>]
[ <exp1>
, …
, <expn>
]

Sequence: (<exp1>; …; <expn>)

(<exp1>; …; <expn>)
( <exp1>
; …
; <expn>
)

❓ The multi-line syntax is uniform with other similar syntaxes, but should it be preferred here? If not, what would be better?

Let Expression: let <dec> in <exp1>; …; <expn> end

let
  <dec>
in
  <exp1>;
  …;
  <expn>
end

❓ Should there be an allowable short-form if <dec> has one declaration? e.g.,

let val x = 21
in 2 * x
end
(* my favorite, I think? *)
let val x = 21
in 2 * x end
let val x = 21 in
2 * x
end
let val x = 21 in
2 * x end

❓ Can we line up the ; placement with the raw sequencing operation?

❓ Does it make sense to support a single-line sequence, e.g.

let
  <dec>
in
  <exp1>; …; <expn>
end

where the <expi>s aren't "too long"?

⚠️ Style Errors
  • Empty <dec>

Parenthesized Expression: (<exp>)

(<exp>)
⚠️ Style Errors

Completely redundant parentheses. These are certainly redundant:

(42)
((42))
(x)
(let val x = 21 in 2 * x end)

These probably shouldn't be considered redundant, although not sure (re conversation with @shwestrick):

((* important constant *) 42)
((* should use x, not y *) x)

exp

TODO

dec

TODO

atpat

TODO

pat

TODO

ty

TODO

Module Language

strexp

Struct: struct <strdec> end

struct end
struct <dec (short)> end
struct
  <strdec>
end

Structure Name: longstrid

<longstrid>

Structure Ascription (Transparent): <strexp> : <sigexp>

<strexp> : <sigexp (short)>
<strexp> :
<sigexp>

Structure Ascription (Opaque): <strexp> :> <sigexp>

<strexp> :> <sigexp (short)>
<strexp> :>
<sigexp>
Examples
struct
  type t = int
  val toString = Int.toString
end :> SHOW where type t = int
struct
  type t = int
  val toString = Int.toString
end :>
sig
  type t = int
  val toString : t -> string
end

Functor Application: <funid> (<strexp>)

<funid> (<strexp (short)>)
<funid> (
  <strexp>
)

Structure Let: let <strdec> in <strexp> end

let
  <strdec>
in
  <strexp>
end
Examples
let
  structure S1 = F (X1)
  structure S2 =
    G (
      structure A = X2
      structure B = X3
    )
in
  struct
    open S1 S2
  end
end
let
  structure S1 = F (X1)
in
  H (val foo = S1.x)
end
let
  structure S1 = F (X1)
in
  H (
    structure S = S1
    val foo = S1.x
  )
end
⚠️ Style Errors
  • Empty <strdec>

strdec

Declaration: dec

<dec>

Structure Declaration: structure <strbind>

structure <strid> = <strexp (short)>
structure <strid> =
  <strexp>

The same rules apply for subsequent and clauses, where and is indented to match the end of structure.

Examples
structure S = struct end
structure S2 = S1
structure S =
  struct
    type t = int
    val x : t = 42
  end
structure S1 = X1
      and S2 = X2

❓ So, things like this should be considered good style? Debatable, but perhaps it's good formatting-level style and just bad programmer style. (Could consider a nonzero number of and clauses with any clause having a non-short exp to be ⚠️ bad style?)

structure S1 =
  struct
    type t = int
    val x : t = 42
  end
      and S2 = X2
      and S3 = Foo (X3)
      and S4 =
  Foo (
    type t = int
    val x : t = 42
  )

Local Definition: local <strdec1> in <strdec2> end

local
  <strdec1>
in
  <strdec2>
end
⚠️ Style Errors
  • Empty <strdec1>

Sequential Definition: <strdec1> <strdec2>

<strdec1>

<strdec2>
⚠️ Style Errors
  • No space between <strdec1> and <strdec2>
  • Semicolon after <strdec1>

sigexp

TODO

sigdec

TODO

@shwestrick
Copy link

Perhaps it would be worthwhile to distinguish "big" and "small" structures for this purpose. The distinction is a bit fuzzy though.

@HarrisonGrodin
Copy link
Author

Hmm... I see your point regarding unnecessary indentation.

Instinctively, I'm not a fan of the "even further" idea, since I think putting the structure declaration at the "same level" as the other declarations can get confusing quickly. (And, it feels like a special case, since presumably putting another structure inside of S should incur more indentation.)

Not sure how I feel about the standard "no indentation" example. Definitely seems more reasonable, but how would this interact with other cases, like functor application? e.g.,

structure S =
Foo (
  type t = int
  val x : t = 42
)

feels odd, but maybe that's just me.

Personally, I don't mind the extra indentation for the sake of uniformity (especially in the case of other top-level decls), but perhaps I'm an edge case?

@shwestrick
Copy link

I also agree I'm not a big fan of completely unindenting the contents. I've seen that syntax in various codebases (MLton is a good example), but I think only for outermost structures which take up a whole file.

Personally, I don't mind treating struct-end differently than functor applications. But perhaps it's actually me that's the edge case ;)

@shwestrick
Copy link

By the way, I think we'll need to assign someone as the executive decision maker in order to settle on something. Would you like to do that?

@HarrisonGrodin
Copy link
Author

I would be delighted to!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment