Skip to content
rvirding edited this page Jul 17, 2011 · 13 revisions

This page contains suggestions for new things for LFE. Please comment.

- Automatically convert atoms with ’ -’ in LFE to ‘_’ in Erlang. This would make most Erlang functions look much more lispy. So what in LFE would look like list-to-atom would really be list_to_atom and we could write (list-to-atom x). If you explicitly wanted a ’ -’ in the atom you could quote it like atom\-with\-hyphens.

I think it would make LFE look much better, but would it be confusing?

Doc strings


     (defun foo (x) 
         "Bla bla...."
         (progn  ...etc  ))

In the generated beam module, two functions function_docs/0 and function_docs/1 would be added.
On calling them they would return:


    M:function_docs()  =>  [foo]    % a list of functions that have a doc string
    M:function_docs(foo)  => "Bla bla...."

Ditch Multi-Expression Bodies

The core forms tend to take multiple expressions as the “body”, evaluated sequentially but only the result of the last one being returned. This approach seems to stem from other Lisp implementations, and has two problems:

1. It relies on side effects. Expressions preceding the last one are only useful if they have side effects, and expressions that exist only for their side effects are very rare in well-written Erlang. At a minimum, the return value must be pattern matched against ‘ok’. This is clearly seen in LFE code, where side effects are usually carried out in a let* rather than a progn.

2. It complicates syntax, necessitating separate styles for pattern matches and non-pattern matches. This steepens the learning curve and makes code look more intimidating – for no particular benefit, due to 1.

The latter can be fixed with new macros (I’m putting together a Clojure-like defn and fn as I write this) but the first is a subtle property of well-written Erlang code, and much harder to encourage.

COMMENT: I think this is an interesting idea but it entails changes in many places. There are a number of core forms which use this: lambda, match-lambda, case, receive, try and progn :-) , and also many of the pre-defined macros like cond and lc. Many macros generate such bodies without actually knowing anything about them. You would probably need to keep progn (and eval-when-compile) for some cases. I would have nothing against such a change but users accept it?

RE: COMMENT There seem to be several categories:

  • Doing fine: progn and eval-when-compile are made for multiple side effects, and fill the role admirably.
  • No main body, works okay: case cond and receive have only clauses. The clauses themselves can have multiple body expressions, which is unlikely to show up in functional code… But the main benefit I see to only allowing one body, is removing the brackets around the clause. And that breaks auto-indentation, which is probably a bad idea. I don’t know whether only allowing one body-expression would encourage more functional code here.
  • Has main body, changes will break compatibility: let and variants. I’m pretty sure let* is second only to defun in frequency of use, and almost never has >1 expression in the body. Restricting these to one body expression would significantly simplify indentation in a lot of code. (Can’t think of an alternate syntax macro that would work. Try and emulate Haskell’s (when body (p1 …) (p2 …) …), but without the closure?)
  • Troubled, but extendable: defun, lambda, and def-lambda suffer from separate syntaxes for pattern matches. New macros can be added to supplant them: this is my attempt. (I think I went overboard in stripping “unnecessary” brackets – clauses should probably be individual expressions for auto-indentation.)
  • Unclassified: I haven’t figured out where try and lc fit in this. (Last I tried try I think I noticed the User Guide having an extra set of brackets.)

Compile Warnings and Errors from Macros

Some library call or convention to stop compilation and tell the user they’ve got the wrong syntax. Currently error and throw work, but are fairly ugly. (And I don’t think rebar likes it when compile workers crash. It seems to eat their error messages.)

COMMENT: This is a good idea and I will put it on my todo list. I will catch errors in macros and have the compiler do a normal error return.

Macro Expansion in Match-Lambda Clauses

If I understand correctly, currently macros are expanded in 1. top-level clauses 2. pattern matches 3. bodies. Thus, if you want to define both a pattern match and a body with a macro, you must use a top-level defun-defining macro.

Doing macro expansion in clauses would allow side effects and extra processing to be attached to pattern matches: pattern match syntax, for more advanced/side effectful code.

Top of the head example would be a pattern-matching packet parser that range checks inputs and prints a warning if out of range.

Curly-Infix, and Modern-Expressions

  • Extend the syntax with infix operators when in curly brackets. Example: (: math sqrt {{x1 * y1} + {x2 * y2}})
  • Treat atoms prefixing an expression as the first term of the expression. Example: {log(x) / log(y)}

Seems like an unpopular choice with Lisp fans, but they’re probably not the target audience anyway – and it would make LFE very competitive with Erlang as far as code readability goes!

See http://www.dwheeler.com/readable/ for detailed description.