Emre Sevinç
Emre Sevinç

Reputation: 8521

What is the reason behind two styles of function definition when using pattern matching in Haskell?

In Chapter 7, "More functional patterns" of Haskell Programming from First Principles, given the following data types:

newtype Username = Username String
newtype AccountNumber = AccountNumber Integer
data User = UnregisteredUser
          | RegisteredUser Username AccountNumber

it defines the following function:

printUser :: User -> IO ()
printUser UnregisteredUser = putStrLn "UnregisteredUser"
printUser (RegisteredUser (Username name)
                          (AccountNumber acctNum))
          = putStrLn $ name ++ " " ++ show acctNum

But experimenting with the code, I realized that I can also define de printUser function as:

printUser :: User -> IO ()
printUser user = case user of
  UnregisteredUser -> putStrLn "UnregisteredUser"
  (RegisteredUser (Username name)
                  (AccountNumber acctNum)) -> putStrLn $ name ++ " " ++ show acctNum

I'm trying to understand why it is possible to use two such different styles. Is there some design motivation behind it? Or, an explanation like, "first style is preferred in such and such situations, whereas the second style of definition would better be used when ..."? (I mean, anything other than a vague 'readability'-motivated explanation?)

Upvotes: 3

Views: 248

Answers (3)

Luis Casillas
Luis Casillas

Reputation: 30227

The answer to this is in the following, highly recommended paper:

In section 4.4 they talk about this:

4.4 Declaration style vs. expression style

As our discussions evolved, it became clear that there were two different styles in which functional programs could be written: “declaration style” and “expression style”. [...]

The declaration style attempts, so far as possible, to define a function by multiple equations, each of which uses pattern matching and/or guards to identify the cases it covers. In contrast, in the expression style a function is built up by composing expressions together to make bigger expressions. [...]

It took some while to identify the stylistic choice as we have done here, but once we had done so, we engaged in furious debate about which style was “better.” An underlying assumption was that if possible there should be “just one way to do something,” so that, for example, having both let and where would be redundant and confusing.

In the end, we abandoned the underlying assumption, and provided full syntactic support for both styles. This may seem like a classic committee decision, but it is one that the present authors believe was a fine choice, and that we now regard as a strength of the language.

So the reason is just that when Haskell was being invented, different authors had different preferences, and they just threw both styles into the language. So use the one you like.

Declaration style does seem to be more popular, although I'd say most people use a mix.

Upvotes: 10

chepner
chepner

Reputation: 531345

In fact, a piecewise function definition is just syntactic sugar for the definition that uses a case expression. A simpler example:

f (Left  l) = eL
f (Right r) = eR

-- ... desugars to:
f x = case x of
    Left  l -> eL
    Right r -> eR

Upvotes: 1

erdeszt
erdeszt

Reputation: 791

The first format is useful if you want to destruct an argument with single constructor because it makes your functions shorter and cleaner. The second version is preferred when you have multiple constructors because if you have to change the name of the function you only have to do it in one place.

Upvotes: 1

Related Questions