April 26, 2012

Making things more Erlangy

In a previous blogpost I wrote a little Erlang to find sequences n, n+1, ..., n+m that have a given sum:

seqwithsum(Goal) ->
  seqwithsum(1, 2, 3, Goal, []).

seqwithsum(Tail, Head, Sum, Goal, L) ->
  if
    Tail + Head > Goal ->
      L;
    Sum < Goal ->
%     advance head
      seqwithsum(Tail, Head+1, Sum+Head+1, Goal, L);
    Sum > Goal ->
%     advance tail
      seqwithsum(Tail+1, Head, Sum-Tail, Goal, L);
    true ->
%     Prepend matching sequence to list and advance tail
      seqwithsum(Tail+1,Head,Sum-Tail,Goal,[{Tail, Head}] ++ L)
end.


I now dislike the code I wrote because of the ugly if-construct. Now that I've read some more and experimented a little I come to the conclusion that this construct, while efficient, is not Erlangy. "If" looks like a language design after-thought. Guards simply have a better feel to them. So here we go:

seqwithsum(Goal) ->
  seqwithsum(1, 2, 3, Goal, []).

seqwithsum(Tail, Head, Sum, Goal, Results) when Sum < Goal ->
  % advance Head
  seqwithsum(Tail, Head+1, Sum+Head+1, Goal, Results);

seqwithsum(Tail, Head, _Sum, Goal, Results) when Tail + Head > Goal ->
  Results;

seqwithsum(Tail, Head, Sum, Goal, Results) when Sum > Goal ->
  %advance Tail
  seqwithsum(Tail+1, Head, Sum-Tail, Goal, Results);

seqwithsum(Tail, Head, Sum, Goal, Results)
  seqwithsum(Tail+1, Head, Sum- Tail, Goal, [{Tail, Head} | Results]).


That's more the way things are supposed to be in Erlang. At least that's my point of view. To me, this looks more elegant than the code using the if-construct.

Be aware that the guards are evaluated in the order in which they occur in the source. Moving the code guarded by Tail + Head > Goal further down will cause an infinite loop.

No comments:

Post a Comment