[erlang-questions] Funargs: Ruby-like blocks for Erlang

Tony Arcieri tony.arcieri@REDACTED
Thu Jul 21 09:39:45 CEST 2011

This is an idea that's been bouncing around in my head for awhile now
and I thought I'd just bust it out:


Raw patch available here (I just grabbed the latest source code off
Github to make this):



There's lots of cases where you just want to pass a single fun as an
argument to a function. By convention this fun is typically passed as
the first argument. However, the problem with Erlang's fun syntax is,
well, it isn't fun. It's kind of noisy, and passing a fun as an
argument makes it even noisier.

Ruby has this really nifty feature called blocks which, to put not too
fine a point on it, provides some awesome syntactic sugar for passing
an anonymous function as an argument to another function. In Ruby,
blocks look like this:

    [1,2,3,4,5].map do |n|
        n * 2

(there are other forms, but this is the one I'm focusing on)

Ask any Rubyist and they'll tell you blocks are the bee's knees. They
are constantly trotted out as one of the most awesome and amazing
features of Ruby. Many attempts have been made to add blocks to
languages like Python (e.g.
http://tav.espians.com/ruby-style-blocks-in-python.html) but it
doesn't work in Python due to quirks in its indent-based grammar.

However, I'd rather ask: can Erlang have something like Ruby like
blocks? Yes, yes it can.


The linked patch implements a feature I'm tentatively calling
"funargs" (yes, I know, this name has prior usage in the funarg
problem. If you don't like it suggest a better one!)

The patch adds a new 'do' keyword and otherwise copies the Ruby syntax
outright. Let's compare what Erlang lets you do now with what the
syntax this patch provides allows.


    mnesia:transaction(fun() ->
        mnesia:write(#thing{foo=1, bar=2, baz=3})


    mnesia:transaction do
        mnesia:write(#thing{foo=1, bar=2, baz=3})

That's marginally better. How about some more examples?


    lists:map(fun(N) ->
        N * 2
    end, [1,2,3,4,5]).


    lists:map([1,2,3,4,5]) do |N|
        N * 2

Again, it's marginally better. What if there are more arguments?


    lists:foldl(fun(Octec, Acc) ->
        Acc bsl 8 bor Octet
    end, 0, [127,0,0,1]).


    lists:foldl(0, [127,0,0,1]) do |Octet, Acc|
        Acc bsl 8 bor Octet

In this case I definitely prefer the latter form. Try to imagine
functions with much more expressions in the fun body.

So I'll admit so far none of these examples are *particularly* more
compelling than their equivalent "fun" forms. Where blocks get really
interesting is when you nest them, particularly when building what
Rubyists refer to as DSLs. Below is a hypothetical example I think
could actually be implemented using this syntax, perhaps with a custom
error handler, which I admit would be a complete hack, but I think
it'd be pretty interesting. I tried to translate an example builder
template from Ruby available here:


Let's imagine we have a custom error handler and a parameterized
module "Xml" which is thunking to a process that's building an XML
document for us on the fly. We could build XML in Erlang as follows:

    Xml:posts do
        lists:each(Posts) do |Post|
            Xml:post do
                Xml:comments do
                    lists:each(Post#post.comments) do |Comment|
                        Xml.comment do

And voila, you have a fairly decent DSL for building XML from Erlang.


Tony Arcieri

More information about the erlang-questions mailing list