Defining a function by equations with different number of arguments

Haskell does it this way because it's predecessors (like LML and Miranda) did. There is no technical reason it has to be like this; equations with fewer arguments could be eta expanded. But having a different number of arguments for different equations is probably a typo rather than intentional, so in this case we ban something sensible&rare to get better error reporting in the common case.


The meaning of a function with multiple clauses is defined by the Haskell standard (section 4.4.3.1) via translation to a lambda and case statement:

fn pat1a pat1b = r1
fn pat2a pat2b = r2

becomes

fn = \a b -> case (a,b) of
  (pat1a, pat1b) -> r1
  (pat2a, pat2b) -> r2

This is so that the function definition/case statement way of doing things is nice and consistent, and the meaning of each isn't specified redundantly and confusingly.

This translation only really makes sense when each clause has the same number of arguments. Of course, there could be extra rules to fix that, but they'd complicate the translation for little gain, since you probably wouldn't want to define things like that anyway, for your readers' sake.


I think it's mainly for consistency so that all clauses can be read in the same manner, so to speak; i.e. every RHS is at the same position in the type of the function. I think would mask quite a few silly errors if you allowed this, too.

There's also a slight semantic quirk: say the compiler padded out such clauses to have the same number of patterns as the other clauses; i.e. your example would become

safeDivide x 0 = x
safeDivide x y = (/) x y

Now consider if the second line had instead been safeDivide = undefined; in the absence of the previous clause, safeDivide would be , but thanks to the eta-expansion performed here, it's \x y -> if y == 0 then x else ⊥ — so safeDivide = undefined does not actually define safeDivide to be ! This seems confusing enough to justify banning such clauses, IMO.

Tags:

Haskell