Online Book Reader

Home Category

Learn You a Haskell for Great Good! - Miran Lipovaca [16]

By Root 469 0
a type must first be an instance of Eq. In other words, being an instance of Eq is a prerequisite for being an instance of Ord. This makes sense if you think about it, because if you can compare two things for ordering, you should also be able to tell if those things are equal.

Chapter 3. Syntax in Functions

In this chapter, we’ll take a look at the syntax that enables you to write Haskell functions in a readable and sensible manner. We’ll look at how to quickly deconstruct values, avoid big if else chains, and store the results of intermediate computations so that you can reuse them multiple times.

Pattern Matching


Pattern matching is used to specify patterns to which some data should conform and to deconstruct the data according to those patterns.

When defining functions in Haskell, you can create separate function bodies for different patterns. This leads to simple, readable code. You can pattern match on pretty much any data type—numbers, characters, lists, tuples, and so on. For example, let’s write a simple function that checks if the number we pass to it is a 7:

lucky :: Int -> String

lucky 7 = "LUCKY NUMBER SEVEN!"

lucky x = "Sorry, you're out of luck, pal!"

When you call lucky, the patterns will be checked from top to bottom. When the passed argument conforms to a specified pattern, the corresponding function body will be used. The only way a number can conform to the first pattern here is if it is a 7. In that case, the function body "LUCKY NUMBER SEVEN!" is used. If it’s not a 7, it falls through to the second pattern, which matches anything and binds it to x.

When we use a name that starts with a lowercase letter (like x, y, or myNumber) in our pattern instead of an actual value (like 7), it will act as a catchall pattern. That pattern will always match the supplied value, and we will be able to refer to that value by the name that we used for the pattern.

The sample function could have also been easily implemented by using an if expression. However, what if we wanted to write a function that takes a number and prints it out as a word if it’s between 1 and 5; otherwise, it prints "Not between 1 and 5"? Without pattern matching, we would need to make a pretty convoluted if/then/else tree. However, pattern matching makes this a simple function to write:

sayMe :: Int -> String

sayMe 1 = "One!"

sayMe 2 = "Two!"

sayMe 3 = "Three!"

sayMe 4 = "Four!"

sayMe 5 = "Five!"

sayMe x = "Not between 1 and 5"

Note that if we moved the last pattern (sayMe x) to the top, the function would always print "Not between 1 and 5", because the numbers wouldn’t have a chance to fall through and be checked for any other patterns.

Remember the factorial function we implemented in the previous chapter? We defined the factorial of a number n as product [1..n]. We can also define a factorial function recursively. A function is defined recursively if it calls itself inside its own definition. The factorial function is usually defined this way in mathematics. We start by saying that the factorial of 0 is 1. Then we state that the factorial of any positive integer is that integer multiplied by the factorial of its predecessor. Here’s how that looks translated into Haskell terms:

factorial :: Int -> Int

factorial 0 = 1

factorial n = n * factorial (n - 1)

This is the first time we’ve defined a function recursively. Recursion is important in Haskell, and we’ll take a closer look at it in Chapter 4.

Pattern matching can also fail. For instance, we can define a function like this:

charName :: Char -> String

charName 'a' = "Albert"

charName 'b' = "Broseph"

charName 'c' = "Cecil"

This function seems to work fine at first. However, if we try to call it with an input that it didn’t expect, we get an error:

ghci> charName 'a'

"Albert"

ghci> charName 'b'

"Broseph"

ghci> charName 'h'

"*** Exception: tut.hs:(53,0)-(55,21): Non-exhaustive patterns in function charName

It complains that we have “non-exhaustive patterns,” and rightfully so. When making patterns, we should always include a catchall pattern at the

Return Main Page Previous Page Next Page

®Online Book Reader