[erlang-questions] closure on function argument

Fred Hebert mononcqc@REDACTED
Sat May 1 21:08:17 CEST 2010


A closure is nothing but a regular function with its own independent scope.
Sorry if the following lines are too basic, I don't know how much you know.
If you already know all the rules about scope, then just skip down to the
end of my post.

Imagine each function as a dictionary of variables.

base() ->
  A = 1,
  B = 3,
  C = 42,
  F = fun(F) ->
          E = 17
          D = E + B
      end.


In base/0, the dictionary contains 3 entries: A, B, C and F. A contains 1, B
contains 3, C contains 42 and F contains the closure/anonymous function.

This anonymous function has its own independent scope. In its scope, there's
the variable E, which is worth 17. Then there's D, which is worth the result
of C + B and finally there's F, which is passed as a parameter.

Here, the variable B has no value in the closure's scope. In this case, it
goes to the parent level. B is worth 3 because the closure was defined
within base/0, and so it can borrow definitions from there. D thus has the
value 17+3, which is 20.

That's because the closure inherits the parent's scope. This means that had
the anonymous function been declared the following way:
F = fun(F) ->
        E = 17
        D = E + B,
        A = 10
    end.

there would have been an error. Here, 'A' isn't defined in the parent's
scope, which has been inherited by the closure. As such, reassigning it the
value '10' breaks the rules of single assignment.

So what about F? F is defined as an argument in the closure. Then it will
take whatever argument the closure takes. It doesn't need to go see in
base/0's scope. In fact, it overwrites that entry. This is why you will get
compiler warnings on such lines.

------ SKIP HERE -------

To answer your question directly, the theory above should explain why 'F =
fun(Y) -> fun(Y) -> ok end end' doesn't give the expected results The second
anonymous function redefines the 'Y' that was in the parent's scope. There
will be no matching possible and doing it through guards really is the only
way I know of to do such pattern matching.

If you do want an exception, you might prefer the form fun(A) -> fun(B) -> A
= B end end, which will return the right value if they match and die
otherwise. They're pretty much the same though.

On Sat, May 1, 2010 at 2:38 PM, Zoltan Lajos Kis <kiszl@REDACTED> wrote:

> Hi,
>
> If I have /F = fun(Y) -> fun(Y) -> ok end end/, and /G = F('z')/, I would
> expect /G/ to be /fun('z') -> ok end/.
> Apparently, it is /fun(Y) -> ok end/, as calling it with any argument
> returns /ok/ and never causes a function clause exception.
> I guess that the inner /Y/ being an argument "automatically" shadows the
> outer one.
>
> A workaround I found is using guards: /F = fun(Y) -> fun(X) when X == Y ->
> ok end end/.
> The question is: is there a way to create a direct binding between the
> inner and outer /Y/'s in the original example?
>
> Thank you,
> Zoltan.
>
>
>


More information about the erlang-questions mailing list