[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