[erlang-questions] conses in erlang?

Richard A. O'Keefe ok@REDACTED
Thu Jul 3 02:41:13 CEST 2008


On 2 Jul 2008, at 8:33 pm, not norwegian swede wrote:
> can i use conses in erlang?

[ H | T ] in Erlang is precisely the same thing as (cons H T) in Scheme.
>
> like in scheme, then i only need one function.
> is the range func in erlang ood erlang-style or is there a better  
> way to do it?

I'm having trouble understanding "range func" and "ood erlang-style".
Is that OOD (Object-Oriented Development) or (g)ood?
>
> (define (seq a b)
>     (if (< a b)
>         (cons a (seq (+ a 1) b))
>         '()))

It is good Scheme style to provide comments.
The missing comment here seems to be

	;; (seq start end) => (start start+1 ... end-1)
	;; that is, the integer interval [start,end).

That's a good definition in Scheme because Scheme uses 0 origin
indexing and uses a [start,end) convention for slices.

In Scheme I might have written

	(define (seq Start End)
	  (do ((I (- End 1) (- I 1))
                (R '()       (cons I R)))
               ((< I Start) R)))

Testing the two versions gave me a real shock:  the "do" version
worked just fine, but the body-recursive version actually crashed
the SCM 5b3 system I was testing in.
>
>
> -module(test).
> -export([range/2]).
>
> range(Start, End) when Start < End, is_integer(Start),  
> is_integer(End) ->
>     seq(Start, End, []).
>
> seq(Start, End, List) ->
>     if Start =< End ->
>         seq(Start + 1, End, List ++ [Start]);
>     true ->
>     List
> end.

The seq/3 function here uses an 'if'; I believe that Erlang style
prefers clause guards to ifs.  So

range(Start, End) when is_integer(Start), is_integer(End) ->
     seq(Start, End, []).

seq(Start, End, List) when Start <= End ->
     seq(Start + 1, End, List ++ [Start]);
seq(_, _, List) ->
     List.

There is an important difference between your Scheme code and
your Erlang code:  they do not compute the same result.  Your
range(1, 4) => [1,2,3,4] whereas
(seq 1 4) => (1 2 3).
Since Erlang uses 1 origin and (sadly) prefers to use
intervals [L,U] rather than [L,U), this is probably what you
meant, but it is definitely important enough to include a
comment to that effect.

The next thing is that Erlang lists are *EXACTLY* like Scheme
lists.  (More precisely, like R6RS lists, which are by
default immutable.)  And L1 ++ L2 is how Erlang expresses
(append L1 L2).  When you are taught Scheme, you are taught
to add new elements at the LEFT end of a list (because that
is O(1)) instead of the right end (because that is O(n)).
[X] ++ L is OK, because it's [X | L] (Scheme `(,X ,@REDACTED)).
L ++ [X] is very seldom a good thing to do.

A recursive version that agrees with your Scheme version,
except for including the upper bound in the result, is

range(Start, End) when is_integer(Start), is_integer(End) ->
     count_up(Start, End).

count_up(Start, End) when Start <= End ->
     [Start | count_up(Start+1, End)];
count_up(_, _) ->
     [].

A tail recursive version like my "do" version is

range(Start, End) when is_integer(Start), is_integer(End) ->
     count_down(Start, End, []).

count_down(Start, End, List) when Start <= End ->
     count_down(Start, End-1, [End|List]);
count_down(_, _, List) ->
     List.




More information about the erlang-questions mailing list