File: part18.lhs

package info (click to toggle)
haskell98-tutorial 200006-3
  • links: PTS
  • area: main
  • in suites: sarge
  • size: 624 kB
  • ctags: 11
  • sloc: haskell: 2,125; makefile: 80; sh: 13
file content (167 lines) | stat: -rw-r--r-- 5,741 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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
Gentle Introduction to Haskell 98, Online Supplement 
Part 18
Covers Sections 9, 9.1, 9.2, 9.3

Section 9.1 Monadic Classes
Section 9.2 Built-in Monads

> module Part18() where 

> e1 = [(x,y) | x <- [1,2,3] , y <- [1,2,3], x /= y]

> e2 = do x <- [1,2,3]
>         y <- [1,2,3]
>         True <- return (x /= y)
>         return (x,y)

> e3 = [1,2,3] >>= (\ x -> [1,2,3] >>= (\y -> return (x/=y) >>=
>      (\r -> case r of True -> return (x,y)
>                       _    -> fail "")))

> mvLift2                :: (a -> b -> c) -> [a] -> [b] -> [c]
> mvLift2 f x y          =  do x' <- x
>                              y' <- y
>                              return (f x' y')

> e4 = mvLift2 (+) [1,3] [10,20,30]
> e5 = mvLift2 (\a b -> [a,b]) "ab" "cd"
> e6 = mvLift2 (*) [1,2,4] []

A quick example using Maybe: first, generalize mvLift2 to all monads:

> lift2'                  :: Monad m => (a -> b -> c) -> m a -> m b -> m c
> lift2' f x y            =  do x' <- x
>                               y' <- y
>                               return (f x' y')

> e7 = lift2' (+) (Just 1) (Just 2)
> e8 = lift2' (+) (Just 1) Nothing

Section 9.3

> type S = Int

> data SM a = SM (S -> (a,S))  -- The monadic type

> instance Monad SM where
>   -- defines state propagation
>   SM c1 >>= fc2         =  SM (\s0 -> let (r,s1) = c1 s0 
>                                           SM c2 = fc2 r in
>                                          c2 s1)
>   return k              =  SM (\s -> (k,s))

>  -- extracts the state from the monad
> readSM                  :: SM S
> readSM                  =  SM (\s -> (s,s))

>  -- extracts the state from the monad
> updateSM                :: (S -> S) -> SM ()  -- alters the state
> updateSM f              =  SM (\s -> ((), f s)) 

> -- run a computation in the SM monad
> runSM                   :: S -> SM a -> (a,S)
> runSM s0 (SM c)         =  c s0

This is fairly hard to demonstrate in a manner that makes this construction
look useful!  This demonstrates the basic operation:

> e9 = runSM 0 (do x <- readSM  -- should be 0
>                  updateSM (+1)
>                  y <- readSM   -- now a 1 
>                  return (x,y))

Most of the SM functions are present in the next example in slightly 
altered forms.

> type Resource           =  Integer

> data R a = R (Resource -> (Resource, Either a (R a)))

> instance Monad R where
>   R c1 >>= fc2          = R (\r -> case c1 r of
>                                 (r', Left v)    -> let R c2 = fc2 v in
>                                                      c2 r'
>                                 (r', Right pc1) -> (r', Right (pc1 >>= fc2)))
>   return v              = R (\r -> (r, (Left v)))

> step                    :: a -> R a
> step v                  =  c where
>                               c = R (\r -> if r /= 0 then (r-1, Left v)
>                                                      else (r, Right c))

> run                     :: Resource -> R a -> Maybe a
> run s (R p)             =  case (p s) of 
>                              (_, Left v) -> Just v
>                              _           -> Nothing

> (|||)                   :: R a -> R a -> R a
> c1 ||| c2               =  oneStep c1 (\c1' -> c2 ||| c1')
>    where
>         oneStep          :: R a -> (R a -> R a) -> R a
>         oneStep (R c1) f =
>              R (\r -> case c1 1 of
>                          (r', Left v) -> (r+r'-1, Left v)
>                          (r', Right c1') ->  -- r' must be 0
>                           let R next = f c1' in
>                             next (r+r'-1))

> lift1                   :: (a -> b) -> (R a -> R b)
> lift1 f                 =  \ra1 -> do a1 <- ra1
>                                       step (f a1)

> lift2                   :: (a -> b -> c) -> (R a -> R b -> R c)
> lift2 f                 =  \ra1 ra2 -> do a1 <- ra1
>                                           a2 <- ra2
>                                           step (f a1 a2)

> (==*)                   :: Ord a => R a -> R a -> R Bool
> (==*)                   =  lift2 (==)

These null instances are needed to allow the definition of Num (R a).

> instance Show (R a) 
> instance Eq (R a) 

> instance Num a => Num (R a) where
>   (+)                   =  lift2 (+)
>   (-)                   =  lift2 (-)
>   negate                =  lift1 negate
>   (*)                   =  lift2 (*)
>   abs                   =  lift1 abs
>   fromInteger           =  return . fromInteger

> ifR                     :: R Bool -> R a -> R a -> R a
> ifR tst thn els         =  do t <- tst
>                               if t then thn else els


> inc                     :: R Integer -> R Integer
> inc x                   =  x + 1

> fact                    :: R Integer -> R Integer
> fact x                  =  ifR (x ==* 0) 1 (x * fact (x-1))

> e10 = run 0 (inc 1)  -- won't complete
> e11 = run 10 (inc 1)  -- will complete
> e12 = run 10 (fact 2)
> e13 = run 10 (fact 20)
> e14 = run 100 (fact (-1) ||| (fact 3))

We can dress this up a little with a nicer "run" function.  This one
adds a little more information:

> run'                    :: Show a => Integer -> R a -> IO ()
> run' maxSteps (R p)     =  case (p maxSteps) of 
>                              (r, Left v) -> putStrLn ("Computed " ++
>                                                        show v ++ " in " ++
>                                                        show (maxSteps-r) ++
>                                                       " steps")
>                              _           -> putStrLn ("Non termination.")

> e15 = run' 100 (fact 3 ||| fact 4)
> e16 = run' 100 (fact (-1) ||| fact 4) 
> e17 = run' 100 (fact 4)



Continued in part19.lhs