Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Different numbers of arguments when pattern matching Maybe

I've run into a problem I don't really understand. I thought that I would be able to write code like this in Haskell:

foo :: Maybe Int -> Int
foo Nothing = 0
foo Just x = x

But when I try to compile it, I get the error:

Equations for ‘foo’ have different numbers of arguments

I can fix it by changing my code to the following:

foo :: Maybe Int -> Int
foo Nothing = 0
foo (Just x) = x

Which makes me think that GHC is interpreting Just as an argument to foo. But Haskell forbids using uppercase letters to start variable names, so I wouldn't think there should be any ambiguity here. What's going on?

like image 511
Rose Kunkel Avatar asked Dec 06 '22 22:12

Rose Kunkel


2 Answers

You're correct, there's not ambiguity about whether or not Just is a constructor – but constructors can have no arguments! Haskell's pattern matching doesn't look up the names involved, it's strictly syntactic, and foo Just x = x is a perfectly well-formed function definition clause. It's ill-typed:

Prelude> let foo Just x = x

<interactive>:2:9:
    Constructor ‘Just’ should have 1 argument, but has been given none
    In the pattern: Just
    In an equation for ‘foo’: foo Just x = x

but with different data types around, it'd be fine:

Prelude> data Justice = Just
Prelude> let foo Just x = x
Prelude> :t foo
foo :: Justice -> t -> t
Prelude> foo Just ()
()

Just could be a nullary constructor (as in the second example), and since function application is left-associative, the compiler parses Just and x as separate arguments and you get the "different numbers of arguments" error. (And as you can see above, if there weren't the Nothing case, you'd actually get the type error for code of that form.)

like image 58
Antal Spector-Zabusky Avatar answered Dec 09 '22 15:12

Antal Spector-Zabusky


The idea is that pattern syntax should mirror application syntax. If I was calling foo I couldn't write foo Just x, because that means something else (and if foo had type (Int -> Maybe Int) -> Int -> Int then it would even work). Having patterns have different rules for where parentheses are needed than expressions would be very weird.

Writing compound patterns without parentheses and trusting the compiler to automatically group things also falls apart in more complex situations. What should this mean?

foo Just x : xs = ...
like image 45
Ben Avatar answered Dec 09 '22 14:12

Ben