File: part10.lhs

package info (click to toggle)
haskell98-tutorial 200006-2-1.1
  • links: PTS
  • area: main
  • in suites: jessie, jessie-kfreebsd, squeeze, wheezy
  • size: 864 kB
  • ctags: 59
  • sloc: haskell: 2,125; makefile: 66; sh: 9
file content (118 lines) | stat: -rw-r--r-- 2,850 bytes parent folder | download | duplicates (6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
Gentle Introduction to Haskell 98, Online Supplement 
Part 10
Covers Sections 4, 4.1, 4.2

> module Part10() where

> import Prelude hiding (take,(^))

Section: 4  Case Expressions and Pattern Matching

Now for details of pattern matching.  We use [Int] instead of [a]
since the only value of type [a] is [].

> contrived :: ([Int], Char, (Int, Float), String, Bool) -> Bool
> contrived ([], 'b', (1, 2.0), "hi", True) = False
> contrived x = True   -- add a second equation to avoid runtime errors

> e1 :: Bool
> e1 = contrived ([], 'b', (1, 2.0), "hi", True)
> e2 :: Bool
> e2 = contrived ([1], 'b', (1, 2.0), "hi", True)

Contrived just tests its input against a big constant.

Linearity in pattern matching implies that patterns can only compare
values with constants.  The following is not valid Haskell:

member x [] = False
member x (x:ys) = True      -- Invalid since x appears twice
member x (y:ys) = member x ys

> f :: [a] -> [a]
> f s@(x:xs) = x:s
> f _ = []

> e3 = f "abc"

Another use of _:

> middle :: (a,b,c) -> b
> middle (_,x,_) = x

> e4 :: Char
> e4 = middle (True, 'a', "123")

> (^) :: Int -> Int -> Int
> x ^ 0 = 1
> x ^ (n+1) = x*(x^n)

> e5 :: Int
> e5 = 3^3
> e6 :: Int
> e6 = 4^(-2)  -- Notice the behavior of the + pattern on this one

Section: 4.1  Pattern Matching Semantics

Here's an extended example to illustrate the left -> right, top -> bottom
semantics of pattern matching.

> foo :: (Int,[Int],Int) -> Int
> foo (1,[2],3)   = 1
> foo (2,(3:_),3) = 2
> foo (1,_,3)     = 3
> foo _           = 4

> e7 = foo (1,[],3)
> e8 = foo (1,error "in e8",3)
> e9 = foo (1,1:(error "in e9"),3)
> e10 = foo (2,error "in e10",2)
> e11 = foo (3,error "in e11 (second)",error "in e11 (third)")

Now add some guards:

> sign :: Int -> Int
> sign x | x > 0  = 1
>        | x == 0 = 0
>        | x < 0  = -1

> e12 = sign 3

The last guard is often `True' to catch all other cases.  The identifier
`otherwise' is defined as True for use in guards:

> max' :: Int -> Int -> Int
> max' x y | x > y      = x
>          | otherwise  = y

Guards can refer to any variables bound by pattern matching.  When
no guard is true, pattern matching resumes at the next equation.  Guards
may also refer to values bound in an associated where declaration.


> inOrder :: [Int] -> Bool
> inOrder (x1:x2:xs) | x1 <= x2 = True
> inOrder _                     = False

> e13 = inOrder [1,2,3]
> e14 = inOrder [2,1]

Section: 4.2  An Example

> take :: Int -> [a] -> [a]
> take 0     _      = []
> take _     []     = []
> take (n+1) (x:xs) = x:take n xs

> take' :: Int -> [a] -> [a]
> take' _     []     = []
> take' 0     _      = []
> take' (n+1) (x:xs) = x:take' n xs

> e15, e16, e17, e18 :: [Int]
> e15 = take 0 (error "e15")
> e16 = take' 0 (error "e16")
> e17 = take (error "e17") []
> e18 = take' (error "e18") []

Continued in part11.lhs