Code for this post is available at 9e7d81b810.

I had written previously that a function in Erie might look like this. After the function name is the list of arguments and their types, followed by the return type, a doc comment, and finally the function body.

(def to_string [result: (Result String Integer)] String
  """
  Convert to result into a printable string to
  be used in interfaces.
  """
  (case result
    [{'ok int} (Integer.to_string int)]
    [{'error str} str]))

After further deliberation, I realized including the argument and return types in the definition makes things a little bit awkward if I want to support pattern matching on the arguments. Not only does it make the types redundant, but the colon syntax gets weird.

(def to_string [{'ok int}: (Result String Integer)] String
  …)

(def to_string [{'error ""}: (Result String Integer)] String
  …)

(def to_string [fallthrough: (Result String Integer)] String
  …)

Including the comment in the function also gets strange when there are multiple clauses for this function. Which of the clauses should the comment be written under?

My latest thinking is to move the types and doc comment out of the definition and into their own lines. Perhaps something like this.

(doc to_string
  """
  Convert a result type into a printable
  string to be used in interfaces.
  """)
(sig to_string (Result String Integer) String)
(def to_string [{'ok int}]
  …)

(def to_string [{'error ""}]
  …)

(def to_string [fallthrough]
  …)

Now the doc and sig lines could be technically written anywhere in the module, but the formatter can move them to the correct location.