Section 9.1 Monadic Classes

Section 9.2 Built-in Monads

第 9.1 节 Monoid 类(Monad 类)

第 9.2 节 内建 Monad

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:

一个用 Maybe 的快速示例:首先,把 mvLift2 推广到所有 monad:

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

第 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.

SM 的大多数函数在下一个示例中会以略有改动的形式再次出现。

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).

这些空实例是定义 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" 函数给它包装一下。这个函数多输出了

一点信息:

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)