So now all I'd like in Erlang is...

Joachim Durchholz joachim.durchholz@REDACTED
Fri Feb 20 11:42:20 CET 2004


Chris Pressey wrote:
> Shawn Pearce <spearce@REDACTED> wrote:
> 
>>Chris Pressey <cpressey@REDACTED> wrote:
>>
>>>How would that work w.r.t. dynamic code reloading?
>>
>>I think it would work just like it does now.  The only difference is
>>that when a module is loaded, rather than registering its exported
>>functions in a table, a module is actually executed.
> 
> OK.  There are still some problems with the approach, though.  Mainly -
> how do you deal with forward references?
> 
> Even self-references in funs currently have to be done like:
> 
>   Fact = fun
>     (_F, N) when N =< 1 ->
>       1;
>     (F, N) ->
>       N * F(N - 1)
>   end,
>   Fact(Fact, 23).

Oh, nice - an embryonic Y combinator :-)
(Y is a bit more general: it will take any function and "recursify" it.)

> There are at least three ways you could deal with this: you could
> adopt Joe's idea for a magical this()-like BIF, or you could do some
> equally magical prediction when you see "Fact = fun" and consider Fact
> to be bound even within the body of the fun, or you could force the
> function to be registered in the export table even if it's solely an
> internal utility.

I must be overlooking something fundamental, so please fill me in where 
the error is:

Assuming the following code:

   Fact = fun
     (N) when N =< 1 -> 1
     (N)             -> Fact (N - 1)
   end,

   Fact (23)

here's my idea of what will (should, actually *g*) happen:

(Never mind the syntax, I'm simply assuming that Fact is a local variable.)

The right side of the "Fact =" assignment is a fun. Internally, that fun 
is just a block of code (bytecode or machine code, details don't really 
matter).
The reference to Fact is compiled into code that says: "retrieve 
whatever is assigned to the name 'Fact'; crash if Fact is either 
unassigned or assigned something other than a fun; evaluate parameters 
and run the fun with them."
At the time that this code block is compiled, the value of Fact is not 
yet known, but that's not a serious problem: it's not run at that time, 
either.
The "Fact (23)" call is compiled just as the recursive call.

At run-time, things (could) happen in this order:
   * Storage is reserved for Fact
   * The fun is loaded as a constant
   * "Fact = ..." executed: reference to fun assigned to Fact variable
   * "Fact (23)" executed:
     - the fun is looked up from the Fact variable
     - the fun is called with a parameter of 23
     - inside the fun, the recursive call again looks for the fun in Fact
     - finds the same fun, calls it with 22
     - etc. until the recursion terminates

The overhead that you have is a lookup in a local variable - an 
operation that's so common that it should be efficient enough :-)


So, my question is: what did I overlook?

> And that's just self-references.  Mutually recursive funs are even more,
> uh, fun :)  They can be done, of course, but they're far from pleasant.

If you handle them in Y-combinator style, then yes... but it's 
straightforward: just add all the functions to the parameter list.

It's still ugly, of course, but no more ugly than a simple 
self-referential function :-)

> I guess what I'm saying is that it *would* be more orthogonal to have
> all functions as funs, but even if we did, it probably wouldn't be long
> before something like foo() -> bar was introduced as a shorthand for
> Foo = fun() -> bar end, register(foo, Foo) anyway.

Actually, if my above description is correct, I'd suggest defining
   foo () -> bar
as a shorthand for
   foo = fun () -> bar
(again, just treating "foo" as a name for a local variable here, not as 
an atom or anything funny).

Regards,
Jo
--
Currently looking for a new job.




More information about the erlang-questions mailing list