tags:

views:

115

answers:

4

For functions where the ordering of the clauses is unimportant, is it base case last:

all(Pred, [Head|Tail]) ->
  case Pred(Head) of
    true -> all(Pred, Tail);
    false -> false
  end;
all(Pred, []) when is_function(Pred, 1) -> true.

Or base case first:

all(Pred, []) when is_function(Pred, 1) -> true;
all(Pred, [Head|Tail]) ->
  case Pred(Head) of
    true -> all(Pred, Tail);
    false -> false
  end.

From looking at the source code in the standard library, it seems the convention is base case last. Is that the preferred style? Is there a reason for it, or is it just the way it is?

+5  A: 

Only the second case will work, as cases are matched in order.

Since the integer 0 is able to match the pattern N, the constant 0 clause would never be reached if it came after.

It is that ordered aspect of pattern-matching which you should think about when writing function clauses, case clauses, or any other such sequence of potential matches.

Justin Sheehy
Whoops, sorry that was a bad example, I meant for a function where the ordering of the clauses doesn't change the behavior. Modified the example to reflect that.
pjb3
+3  A: 

It has semantic meaning how the clauses are ordered. Since patterns are attempted in sequential order.

I tend to put base-cases first since I think it makes it more readable. To already know the base cases when reading the recursive part.

Sometimes I get the feeling that some code have put the most common pattern first, to save the most common case from having to test patterns that it will not likely match.

Christian
Yeah, I agree. Having the base case first makes more sense to me, but that's not how it is in the standard library. Appears there may not be a consensus within the community on this?
pjb3
A: 

Considering that function clauses are checked sequentially, base cases should come first, unless you use guard clauses. Your example should be:

fact(N) when N>0 -> N * fact(N-1);
fact(1)          -> 1.
outis
+2  A: 

With [|] and [] I always put the base case(s) first, and the nil case(s) last, as in your first case. I think this much clearer and more natural. One reason for doing the opposite may be that it more resembles the more general pattern matching where you have the more specific cases first so as to catch them; here [] would be like the more specific case. Just guessing though.

rvirding
From a micro-(or rather nano-)optimization point of view, is there any benefit of ordering clauses by their expected hit-ratio? For example I suppose all() will more often be called with a non-empty list than an empty one.
Zed
It won't hurt, but the compiler will often re-order clauses when it is compiling pattern matching. NOT so that it affects the semantics of course. It depends on what the patterns look like.
rvirding