Syntax in Functions
Pattern Matching
Section titled “Pattern Matching”Haskell supports pattern matching expressions in both function definition and through case statements.
A case statement is much like a switch in other languages, except it supports all of Haskell’s types.
Let’s start simple:
longName :: String -> StringlongName name = case name of "Alex" -> "Alexander" "Jenny" -> "Jennifer" _ -> "Unknown" -- the "default" case, if you likeOr, we could define our function like an equation which would be pattern matching, just without using a case statement:
longName "Alex" = "Alexander"longName "Jenny" = "Jennifer"longName _ = "Unknown"A more common example is with the Maybe type:
data Person = Person { name :: String, petName :: (Maybe String) }
hasPet :: Person -> BoolhasPet (Person _ Nothing) = FalsehasPet _ = True -- Maybe can only take `Just a` or `Nothing`, so this wildcard sufficesPattern matching can also be used on lists:
isEmptyList :: [a] -> BoolisEmptyList [] = TrueisEmptyList _ = False
addFirstTwoItems :: [Int] -> [Int]addFirstTwoItems [] = []addFirstTwoItems (x:[]) = [x]addFirstTwoItems (x:y:ys) = (x + y) : ysActually, Pattern Matching can be used on any constructor for any type class.
E.g. the constructor for lists is : and for tuples ,
Using where and guards
Section titled “Using where and guards”Given this function:
annualSalaryCalc :: (RealFloat a) => a -> a -> StringannualSalaryCalc hourlyRate weekHoursOfWork | hourlyRate * (weekHoursOfWork * 52) <= 40000 = "Poor child, try to get another job" | hourlyRate * (weekHoursOfWork * 52) <= 120000 = "Money, Money, Money!" | hourlyRate * (weekHoursOfWork * 52) <= 200000 = "Ri¢hie Ri¢h" | otherwise = "Hello Elon Musk!"We can use where to avoid the repetition and make our code more readable. See the alternative function below, using where:
annualSalaryCalc' :: (RealFloat a) => a -> a -> StringannualSalaryCalc' hourlyRate weekHoursOfWork | annualSalary <= smallSalary = "Poor child, try to get another job" | annualSalary <= mediumSalary = "Money, Money, Money!" | annualSalary <= highSalary = "Ri¢hie Ri¢h" | otherwise = "Hello Elon Musk!" where annualSalary = hourlyRate * (weekHoursOfWork * 52) (smallSalary, mediumSalary, highSalary) = (40000, 120000, 200000)As observed, we used the where in the end of the function body eliminating the repetition of the calculation (hourlyRate * (weekHoursOfWork * 52)) and we also used where to organize the salary range.
The naming of common sub-expressions can also be achieved with let expressions, but only the where syntax makes it possible for guards to refer to those named sub-expressions.
Guards
Section titled “Guards”A function can be defined using guards, which can be thought of classifying behaviour according to input.
Take the following function definition:
absolute :: Int -> Int -- definition restricted to Ints for simplicityabsolute n = if (n < 0) then (-n) else nWe can rearrange it using guards:
absolute :: Int -> Intabsolute n | n < 0 = -n | otherwise = nIn this context otherwise is a meaningful alias for True, so it should always be the last guard.