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