[erlang-questions] re cursive fun()

Richard O'Keefe ok@REDACTED
Thu Oct 9 04:13:23 CEST 2008

On 8 Oct 2008, at 12:32 am, Hynek Vychodil wrote:
> Is there any problem write this think this way?
> F = begin
>       Outher  = fun(OSelf, ...) ->
>           ...
>           Inner = fun(ISelf, ....) ->
>              ... ISelf(ISelf, X) ...
>              ... OSelf(OSelf, Y) ...
>           end,
>       ... OSelf(OSelf, ...) ... Inner(Inner, ...) ...
>       fun(Args) -> Outher(Outher, Args) end
>   end.

Given that the topic under discussion was syntactic support
to enable the *direct* representation of recursive functions,
yes.  I agree that we *can* get the effect right now without
any extensions at all to the language.  The result can most
charitably be described as unclear and error-prone.

Really, if you want a recursive function, there is no better
way to write it than as a plain ordinary Erlang function.

As for writing functions in the shell, it is so easy to have
an editor in another window letting you write and edit any
number of functions and then just using c(...) in the shell
that there doesn't seem to be any real point in trying to
write non-trivial functions in the shell.

By the way, my understanding is that "begin" and "end" in
Erlang are, as a pair, precisely equivalent to "(" and ")".

> For Example factorial:
> Fact = begin F = fun(_, 0) -> 1; (Self, N) -> Self(Self, N-1)*N end,  
> fun(N) -> F(F, N) end end.

A couple of days ago a 56-year-old member of this university was killed
in a tramping accident.  She and her teenage daughter were tramping in
one of the national parks in the North Island, which has been having
some heavy weather recently.  Apparently the park people warned her of
the the effect the weather had been having on the rivers, and told her
of an alternative, safer, route.  The route this experienced tramper
chose involved a river crossing.  The river was swollen with the rain,
and swept her away.  Her daughter immediately called for help on a
mobile phone, but it was already too late.

What has this to do with programming in Erlang?
When you've made a mistake, you need TIME to notice and recover.

If you've typed something in an editor window,
you have *time* to look at it, to check it,
to think "maybe this could do a bit more checking".
And if you get it wrong, you have it there to fix.  But if you
type something in the shell, you are under subtle pressure to
do it quickly and briefly.  Note, for example, the difference
in how Hynek Vychodil's two examples were laid out.  I'm sure
that in an edit window he would write something _at least_ as
good as

	factorial(N) when N > 0 -> N * factorial(N-1);
	factorial(0)            -> 1.

> Some nontrivial example:
> 4> UpToGen = begin
>               Outher = fun(_OSelf, M, M) -> [];
>                                 (OSelf, Step, M) ->
>                                      Inner = fun(_ISelf, N) when N>M  
> -> [];
>                                                     (ISelf, N) -> [N  
> | ISelf(ISelf, N+Step) ]
>                                      end,
>                                [Inner(Inner, 0) | OSelf(OSelf, Step 
> +1, M)]
>               end,
>               fun(Max) -> Outher(Outher, 1, Max) end
>     end.

This must have been done with tabs set to something other than
the standard 8.  The problem is that I cannot tell what it is
supposed to do without far more work than I have time for right
now.  What I *can* say is that it looks like a textbook example
of something that should not have been written that way.
> #Fun<erl_eval.6.13229925>
> 5> UpToGen(10).
> [[0,1,2,3,4,5,6,7,8,9,10],
>  [0,2,4,6,8,10],
>  [0,3,6,9],
>  [0,4,8],
>  [0,5,10],
>  [0,6],
>  [0,7],
>  [0,8],
>  [0,9]]

To get this particular result, one does

     [lists:seq(0, 10, Step) || Step <- lists:seq(1, 9)]

at to get the general version,

     U = fun (N) ->
	[lists:seq(0, N, Step) || Step <- lists:seq(1, N-1)]

will do fine.  Even factorial can be done as

     F = fun (N) ->
	lists:foldl(fun (X, Y) -> X * Y end, 1, lists:seq(1, N))

Or rather, this *WOULD* work if it weren't for the
lists:seq(1, 0) bug that I have complained about before.
Similarly, U(1) *ought* to be the empty list, but thanks
to the lists:seq(1, 0) but it crashes.
People, it really is time to fix that bug.

More information about the erlang-questions mailing list