[erlang-questions] Clueless am I

Richard A. O'Keefe ok@REDACTED
Wed Apr 27 02:45:19 CEST 2016



On 27/04/16 5:45 AM, duncan@REDACTED wrote:
> One thing that helped me as a beginner wrt the 'immutable variable', 
> and I think will help with understanding this whole thread, is that 
> the C mindset contains not only the 'mutable variable' but also the 
> 'loop' construct. It's important to note there are no loops in erlang. 
> Even though 'loop' is used in the post below, it's not a c-like loop - 
> it's a function call.
Pop-2 had two "if"-like constructs:

     if E1 then S1 {elseif E2 then S2}... [else S0] close

     loopif E1 then S1 {elseif E2 then S2}... [else S0] close

Then conditions E1... are tested in the order written and when Ei turns
out to be true, the corresponding Si is executed.
loopif is the same as if except that if any Si is executed, control 
returns to the
beginning.  (If there's an 'else' in there, this means you had better 
have a 'return'
somewhere to stop the loop.)

Dijkstra's classic "A Discipline of Programming" had two "if"-like 
constructs:

     if E1 -> S1 {[] E2 -> S2}... fi
     do E1 -> S1 {[] E2 -> S2}... od

The conditions E1... may be tested in order; "[] E2 -> S2" does *not* get to
assume that E1 is false.  If no Ei is true, "if" reports an error and 
"do" stops.
Otherwise, "do" is just like "if" except that each Si will branch back 
to the
beginning.

Now Erlang doesn't really have an equivalent of "if". Erlang's basic control
structure is "case":
     case E
       of P1 when G1 -> S1
        ; ...
        ; Pn when Gn -> Sn
     end
If we wrap that in a function,

     trichoplusia(Parameters) ->
         case E
           of P1 when G1 -> S1, trichoplusia(Parameters')
            ; ...
            ; Pn when Gn -> Sn, trichoplusia(Parameters')
            ; _ -> Result
         end.

(trichoplusia?  The cabbage looper.)

what we get is *precisely* a Dijkstra/Pop-2 multibranch loop.

Let's take a simple C-like program for summing the elements
of an array.

     n = size of the array;
     i = 0;
     s = 0;
     while (i < n) s += array[i], i += 1;
     return s;

Now let's turn that into Erlang, allowing for the fact that Erlang
tuples are indexed from 1.

     sum(tuple_size(Tuple), 1, 0, Tuple)

where

     sum(N, I, S, T) ->
       if N < I -> S
        ; true  -> sum(N, I+1, S+element(I,S), T)
       end.

Thanks to last call optimisation, the recursive call to sum/4
is just "assign updated values to parameters and JUMP".  From
where I stand, this *IS* a while loop.  (More precisely, a while
loop is a not-very-interesting special case of a multiway
loop.)

C has loop over x, erlang has recurse over x.

I suppose the battle is lost, but the verb that "recursion" is derived from
is "recurrere" from which we get "recur".  It's "recur" + "tion". English
"Recurse" is an ugly and pointless back-formation.

Recurring function calls are the *primitive* mechanism that
functional programming languages use to build traversals of
recursively defined data structures.  It is useful to write
them out when learning a language, to show yourself there's
no magic.  In practice, you want to package common patterns
up as higher order functions, and write as little recursive
code of your own as you practically can.

For example, a better way to handle summing the elements of
a tuple is to separate that into "folding" over a tuple and
an application of that:

tuple_foldl(Fun, Acc, Tuple) ->
     tuple_foldl_aux(Fun, Acc, Tuple, 1, tuple_size(Tuple)).

tuple_foldl_aux(Fun, Acc, Tuple, I, N) ->
     if N < I -> Acc
      ; true  -> tuple_foldl_aux(Fun,
                    Fun(element(I, Tuple), Acc), Tuple, I+1, N)
     end.

sum(Tuple) ->
     tuple_foldl(fun (E, S) -> S+E end, 0, Tuple).

Why is this better?  Because tuple_foldl/3 and its helper
function can go in a library module and their details
forgotten.  From then on, when you want to combine the
elements of a tuple, all you have to do is figure out
what the result should be for no elements, and how to
combine one more element into a running totl, and you're
done.  Your code becomes "index-free".  You don't make
any indexing mistakes.





More information about the erlang-questions mailing list