first commit
mhe authored 1 week ago
functions.md 11.22 KiB
Functions in Haskell
Copyright By PowCoder代写 加微信 powcoder
• Read also Chapter 4 of the text book “Programming in Haskell.
In this lesson, we study various ways how functions can be defined in Haskell. We will study the following
1. Composition of existing functions
2. Conditionals ( if _ then _ else _ ) 3. Guarded equations
4. Pattern matching
5. Lambda expressions
At the end, we will also look at operators (infix function symbols such as Composing functions
A video for this section, including explanation of the exercise, is here. We can compose existing functions to get new ones. For instance:
removeLast :: [a] -> [a]
removeLast xs = reverse (tail (reverse xs))
removeElem :: Int -> [a] -> [a]
removeElem n xs = removeLast (take n xs) ++ drop n xs
++ ), and how to turn them into fu
Exercise: Using the functions above, write a function that removes both the first and the last element of a li Conditionals
Haskell provides if _ then _ else _ . It is typed Bool -> a -> a -> a , polymorphically.
abs’ :: Integer -> Integer
abs’ n = if n >= 0 then n else -n
notB :: Bool -> Bool notB False = True
Note: The else branch is mandatory. We can nest if _ then _ else _ :
howMuchDoYouLikeHaskell :: Int -> String howMuchDoYouLikeHaskell x = if x < 3 then "I dislike it!" else
if x < 7 then "It's ok!" else "It's fun!"
This is difficult to read, however; guarded equations (see below) can be more pleasant to read. We will avoid cond Exercise: Read the discussion about if _ then _ else _ on the Haskell wiki.
Guarded equations
A video for this section, including explanation for the exercise, is here.
Guarded equations are an alternative to if _ then _ else _ expressions. They are often more readable:
abs :: Int -> Int
Here, n >= 0 and otherwise are called guards; they are Booleans. The function returns the value after the
Guarded equations are more convenient to use than if _ then _ else _ :
howMuchDoYouLikeHaskell2 :: Int -> String howMuchDoYouLikeHaskell2 x |
| otherwise
= “I dislike it!” = “It’s ok!”
= “It’s fun!”
Exercise: Using guarded equations, write a function of type Int -> Int -> Bool that returns True if the and less than twice the second.
Pattern matching
Pattern matching analyses the input according to how it is built. The input is matched against a sequence of patte
determines the output of the function.
There are only two possibilities for what a Boolean value can be: True or False . It is hence sufficient to ha
| otherwise
notB True = False
There is only one way to make a pair:
swap :: (a, b) -> (b, a) swap (x,y) = (y,x)
There are two ways to make a list:
isEmpty :: [a] -> Bool isEmpty [] = True isEmpty (x:xs) = False
We will look at all of these in detail now.
On Booleans
One of the simplest patterns is to match for Booleans.
If the input is just one Boolean, there are only two patterns:
notB’ :: Bool -> Bool notB’ False = True notB’ True = False
If a function takes two Booleans as input, there are 2^2 = 4 patterns:
andB :: Bool -> Bool -> Bool andB True True = True
andB True False = False
andB False True = False
andB False False = False
The last three patterns can be combined. Here, the wildcard pattern _
andB’ :: Bool -> Bool -> Bool andB’ True True = True
andB’ _ _ = False
matches anything, and discards it:
There is a difference between these two versions: in the latter, if the first argument is False , then the seco evaluated: False is returned immediately.
In the next example, the pattern b matches anything. However, in contrast to _ , we can use b on the righ
andB” :: Bool -> Bool -> Bool andB” True b = b
andB” False _ = False
Exercise: Write a function orB :: Bool -> Bool -> Bool that returns True if at least one argument is Non-exhaustive patterns
Consider the following example:
isTrue :: Bool -> Bool isTrue True = True
Question: What will isTrue False evaluate to?
Answer: This is a non-exhaustive pattern, and isTrue False will raise an exception:
*Main> isTrue False
*** Exception: defining-functions.hs:36:1-18: Non-exhaustive patterns in function isTru
We can choose to throw a custom-made exception instead:
isTrue’ :: Bool -> Bool
isTrue’ True = True
isTrue’ False = error “not True”
If the function we are defining expects as input a tuple, we can match against the individual components:
fst :: (a,b) -> a fst (x,y) = x
We actually don’t use y in the output of the function, so we can use fst (x,_) = x instead. Similarly, snd :: (a,b) -> b
snd (_,y) = y
This generalizes to tuples of three or more components:
third :: (a, b, c) -> c third (_, _, z) = z
We can match several tuples at the same time:
addVectors :: (Num a) => (a, a) -> (a, a) -> (a, a) addVectors (x1, y1) (x2, y2) = (x1 + x2, y1 + y2)
Exercise: Write a function swap :: (a, b) -> (b, a) that swaps the elements of a pair.
See also this video.
All lists are built by prepending (:) , successively, elements to an existing list, starting with the empty list
been obtained as 1:[2,3] , etc. – [1, 2, 3] is short for 1:(2:(3:[])) . In other words, every list in [a] 1. the empty list; or
2. of the form x:xs for x :: a and xs :: [a] .
isEmpty’ :: [a] -> Bool isEmpty’ [] = True isEmpty’ (x:xs) = False
We are not actually using x or xs in the output of the second pattern, so we can write the function more simply
isEmpty” :: [a] -> Bool isEmpty” [] = True isEmpty” (_:_) = False
Note that the parentheses around _:_ in the second pattern are necessary! We can write more complex list patterns. To return the second element of a list:
sndElem :: [a] -> a sndElem (_:x:_) = x
Case expressions
The aforementioned patterns are special forms, for Booleans, and lists. The general form for such pattern matchi
isEmpty2 :: [a] -> Bool
isEmpty2 x = case x of [] -> True
(_:_) -> False
Here, it is important that all the patterns are exactly aligned, i.e., the [] and (_:_) must start in exactly the sa
Lambda expressions
Lambda expressions are nameless functions. They are particularly useful in higher-order functions, which will be
accompanying this section is here.
Lambda expressions are of the form \ ->
2. on Sections Summary
1. We have seen several ways to define functions: composition, conditionals, guard equations, pattern matching
2. When patterns are not exhaustive, functions raise an exception whenever no pattern matches. To avoid this, o
pattern at the end.
3. Any pattern matching can be expressed using a case expression.
4. Anonymous functions can concisely be written using lambda expressions.
程序代写 CS代考 加微信: powcoder QQ: 1823890830 Email: powcoder@163.com