28

I noticed today that such a definition

safeDivide x 0 = x
safeDivide = (/)

is not possible. I am just curious what the (good) reason behind this is. There must be a very good one (it's Haskell after all :)).

Note: I am not looking suggestions for alternative implementations to the code above, it's a simple example to demonstrate my point.

ehird
  • 40,602
  • 3
  • 180
  • 182
aelguindy
  • 3,703
  • 24
  • 31
  • 5
    You call that "safe"? Let it return a `Maybe` or something, or throw some known exception, or use it on a `newtype` that's exclusively for non-degenerate functions you treat as members of e.g. the L² Hilbert space (i.e. only defined modulo null sets); that would be safe. Just defining `x/0=x` _ad hoc_ for all `Fractional` instances is horribly uncanonical! — Well, it was probably only meant as an example. – leftaroundabout Jan 05 '12 at 18:21
  • 1
    +1 Wow, been using Haskell for years and never noticed that such definition is not allowed! – is7s Jan 05 '12 at 19:30
  • @leftaroundabout `safeDivide x 0 = Nothing; safeDivide = Just .: (/)` better? :) – Dan Burton Jan 06 '12 at 01:13
  • 1
    @DanBurton that looks better. You [can't define it this way](http://stackoverflow.com/questions/8745597/defining-a-function-by-equations-with-different-number-of-arguments), though... – leftaroundabout Jan 06 '12 at 01:20
  • @leftaroundabout yes, that's the point xD to define a version thats actually "safe", and still present the same issue. – Dan Burton Jan 06 '12 at 01:34

3 Answers3

29

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.

Enlico
  • 23,259
  • 6
  • 48
  • 102
ehird
  • 40,602
  • 3
  • 180
  • 182
  • So is there no deeper technical reason? – aelguindy Jan 05 '12 at 16:14
  • Thanks for the code formatting edit :), will do that from now on. It took me a while to get why it's const (const \bot), but now I get it. – aelguindy Jan 05 '12 at 16:31
  • @aelguindy: Yeah, I've edited my answer to hopefully clarify that a bit — `⊥` vs. `const ⊥` is especially tricky since they can only be distinguished with `seq`. Glad I could help :) – ehird Jan 05 '12 at 16:32
  • Had I hit refresh earlier.. :). Thanks! – aelguindy Jan 05 '12 at 16:36
15

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.

Ben Millwood
  • 6,754
  • 24
  • 45
5

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.

augustss
  • 22,884
  • 5
  • 56
  • 93