Patterns are very useful, to write clear
and precise applications. In pattern matching, we attempt to match values
against patterns, bind variables to successful matches.
You can perform pattern matching on any
kind of data like tuples, lists, numbers, String etc., For Example, You want to
give points to students based on their scores.
Grade
|
Points
|
1
|
10
|
2
|
9
|
3
|
8
|
Other
|
5
|
points.hs
pointsforGrade 1 = 10 pointsforGrade 2 = 9 pointsforGrade 3 = 8 pointsforGrade x = 5
*Main> :load points.hs [1 of 1] Compiling Main ( points.hs, interpreted ) Ok, modules loaded: Main. *Main> *Main> pointsforGrade 1 10 *Main> *Main> pointsforGrade 54 5 *Main> *Main> pointsforGrade 3 8 *Main>
When you call pointsforGrade, the
patterns will be checked from top to bottom and when it matches to a pattern,
corresponding body is executed.
'pointsforGrade 1' matches to value 10
'pointsforGrade 2' matches to value 9, 'pointsforGrade 3' matches to value 8,
any other arguments to the function 'pointsforGrade' are matches to value 5.
Without pattern matching, we have to
write the code using if-else statement (or) by using guards like below. Most of
the times myself, I prefers write code using pattern matching and guards.
points.hs
pointsforGrade x | (x == 1) = 10 | (x == 2) = 9 | (x == 3) = 8 | otherwise = 5
*Main> :load points.hs [1 of 1] Compiling Main ( points.hs, interpreted ) Ok, modules loaded: Main. *Main> *Main> pointsforGrade 1 10 *Main> *Main> pointsforGrade 4 5
Since patterns are evaluated from top to
bottom, make sure you write specific patterns first, generic patterns next. For
example, if you write the code like below, whatever you pass as argument to the
function pointsforGrade, it always returns value 5.
points.hs
pointsforGrade x = 5 pointsforGrade 1 = 10 pointsforGrade 2 = 9 pointsforGrade 3 = 8
*Main> :load points.hs [1 of 1] Compiling Main ( points.hs, interpreted ) points.hs:1:1: Warning: Pattern match(es) are overlapped In an equation for ‘pointsforGrade’: pointsforGrade 1 = ... pointsforGrade 2 = ... pointsforGrade 3 = ... Ok, modules loaded: Main. *Main> *Main> pointsforGrade 1 5 *Main> pointsforGrade 2 5 *Main> pointsforGrade 100 5
Observe above snippet, Haskell generates
a warning message "patterns are overlapped". Always specify the most
specific ones first and then the more general ones later.
What
if don’t specify general pattern?
Suppose if you specified most specific
patterns and forgot to specify the general one, then pattern match will thrown
an exception, when you try to match for any non-specific value.
points.hs
pointsforGrade 1 = 10 pointsforGrade 2 = 9 pointsforGrade 3 = 8
*Main> :load points.hs [1 of 1] Compiling Main ( points.hs, interpreted ) Ok, modules loaded: Main. *Main> *Main> pointsforGrade 1 10 *Main> *Main> pointsforGrade 3 8 *Main> *Main> pointsforGrade 5 *** Exception: points.hs:(1,1)-(3,20): Non-exhaustive patterns in function pointsforGrade
Observe above snippet, when i called
'pointsforGrade 5', it throws an exception; it is because there is no matched
pattern for the value 5. So whenever you are using patterns, always include a
catch-all pattern so that our program doesn't crash if we get some unexpected
input.
Applying
pattern matching to Lists
[] matches to empty list, pattern like
x:tempList bind the head of list to x, remaining elements of list to tempList.
listPattern.hs
getHead (x:xs) = x getSecond (x:y:xs) = y getTail (x:xs) = xs
*Main> :load listPattern.hs [1 of 1] Compiling Main ( listPattern.hs, interpreted ) Ok, modules loaded: Main. *Main> *Main> getHead [2, 3, 5, 7, 11] 2 *Main> *Main> getSecond [2, 3, 5, 7, 11] 3 *Main> *Main> getTail [2, 3, 5, 7, 11] [3,5,7,11]
Following function displays different
messages based on the number of elements in the list.
Number
of elements in List
|
Message
|
0
|
The list is empty
|
1
|
List has one element
|
2
|
List has two elements
|
>2
|
List has more than two elements
|
listInfo.hs
info [] = "The list is empty" info (x:[]) = "List has one element" info (x:y:[]) = "List has two elements" info(x:y:_) = "List has more than two elements"
*Main> :load listInfo.hs [1 of 1] Compiling Main ( listInfo.hs, interpreted ) Ok, modules loaded: Main. *Main> *Main> info [] "The list is empty" *Main> *Main> info [2, 3, 5, 7] "List has more than two elements" *Main> *Main> info [2, 3] "List has two elements" *Main> *Main> info [2] "List has one element"
Find Number of elements in the list
listLength.hs
listLength ([]) = 0 listLength (x:xs) = 1 + length (xs)
*Main> :load listLength.hs [1 of 1] Compiling Main ( listLength.hs, interpreted ) Ok, modules loaded: Main. *Main> *Main> listLength [] 0 *Main> *Main> listLength [2, 3, 5, 7] 4 *Main> *Main> listLength [2, 3, 5, 7, 11] 5
Find sum of elements in list
sumOfElements.hs
sumOfElements ([]) = 0 sumOfElements (x:xs) = x + sumOfElements (xs)
*Main> :load sumOfElements.hs [1 of 1] Compiling Main ( sumOfElements.hs, interpreted ) Ok, modules loaded: Main. *Main> *Main> sumOfElements [] 0 *Main> *Main> sumOfElements [2, 3, 5] 10 *Main> *Main> sumOfElements [2, 3, 5, -10] 0
Find sum of squares of all elements in the list.
sumOfSquares.hs
square x = x * x sumOfSquares [] = 0 sumOfSquares (x:xs) = square (x) + sumOfSquares (xs)
Prelude> :load sumOfSquares.hs [1 of 1] Compiling Main ( sumOfSquares.hs, interpreted ) Ok, modules loaded: Main. *Main> *Main> sumOfSquares [] 0 *Main> sumOfSquares [2, 3] 13 *Main> sumOfSquares [2, 3, 5, -10] 138
Multiply each element of list by 9
multiply.hs
multiplyBy9 x = (9 * x) map1 fun [] = [] map1 fun (x:xs) = (multiplyBy9 x) : (map1 fun xs)
*Main> :load multiply.hs [1 of 1] Compiling Main ( multiply.hs, interpreted ) Ok, modules loaded: Main. *Main> *Main> map1 multiplyBy9 [2, 3, 5, 7] [18,27,45,63] *Main> *Main> map1 multiplyBy9 [2, 3, 5, 7, -7, 0] [18,27,45,63,-63,0]
Drop first three elements of a list
drop.hs
dropEle (x:y:z:xs) = xs dropEle (xs) = xs
*Main> :load drop.hs [1 of 1] Compiling Main ( drop.hs, interpreted ) Ok, modules loaded: Main. *Main> *Main> dropEle [2] [2] *Main> *Main> dropEle [2, 3] [2,3] *Main> *Main> dropEle [2, 3, 5] [] *Main> *Main> dropEle [2, 3, 5, 7] [7] *Main> *Main> dropEle [2, 3, 5, 7, 11] [7,11]
No comments:
Post a Comment