-- Reader is a monad
instance Monad (Reader env)
-- and we have a function to get its environment
ask :: Reader env env
-- finally, we can run a Reader
runReader :: Reader env a -> env -> a
import Control.Monad.Reader
data GameState = NotOver | FirstPlayerWin | SecondPlayerWin | Tie
data Game position
= Game {
getNext :: position -> [position],
getState :: position -> GameState
}
getNext' :: position -> Reader (Game position) [position]
getNext' position
= do game <- ask
return $ getNext game position
getState' :: position -> Reader (Game position) GameState
getState' position
= do game <- ask
return $ getState game position
negamax :: Double -> position -> Reader (Game position) Double
negamax color position
= do state <- getState' position
case state of
FirstPlayerWin -> return color
SecondPlayerWin -> return $ negate color
Tie -> return 0
NotOver -> do possible <- getNext' position
values <- mapM ((liftM negate) . negamax (negate color)) possible
return $ maximum values
interp' :: Term -> Reader Env Value
--when we have a lambda term, we can just return it
interp' (Lambda nv t)
= do env <- ask
return $ Lam nv (t, env)
--when we run into a value, we look it up in the environment
interp' (Var v)
= do (Env env) <- ask
case lookup (show v) env of
-- if it is not in the environment we have a problem
Nothing -> return . Failure $ "unbound variable: " ++ (show v)
-- if it is in the environment, then we should interpret it
Just (term, env) -> local (const env) $ interp' term
--the complicated case is an application
interp' (Apply t1 t2)
= do v1 <- interp' t1
case v1 of
Failure s -> return (Failure s)
Lam nv clos -> local (\(Env ls) -> Env ((nv, clos) : ls)) $ interp' t2
--I guess not that complicated!
最后,我们可以通过传递一个简单的环境来使用它:
interp :: Term -> Value
interp term = runReader (interp' term) (Env [])
import Control.Applicative
-- | A History with timeline type t and value type a.
newtype History t a = History { observe :: t -> a }
instance Functor (History t) where
-- Apply a function to the contents of a historical value
fmap f hist = History (f . observe hist)
instance Applicative (History t) where
-- A "pure" History is one that has the same value at all points in time
pure = History . const
-- This applies a function that changes over time to a value that also
-- changes, by observing both at the same point in time.
ff <*> fx = History $ \t -> (observe ff t) (observe fx t)
instance Monad (History t) where
return = pure
ma >>= f = History $ \t -> observe (f (observe ma t)) t
Applicative实例意味着,如果你有 employees :: History Day [Person]和 customers :: History Day [Person],你可以这样做:
-- | For any given day, the list of employees followed by the customers
employeesAndCustomers :: History Day [Person]
employeesAndCustomers = (++) <$> employees <*> customers
也就是说,Functor和 Applicative允许我们调整常规的、非历史的功能来处理历史。
通过考虑函数 (>=>) :: Monad m => (a -> m b) -> (b -> m c) -> a -> m c,可以最直观地理解单子实例。a -> History t b类型的函数是一个将 a映射到 b值的历史的函数; 例如,您可以使用 getSupervisor :: Person -> History Day Supervisor和 getVP :: Supervisor -> History Day VP。因此,History的 Monad 实例是关于组合这样的函数的; 例如,getSupervisor >=> getVP :: Person -> History Day VP是一个函数,对于任何 Person来说,它可以获取 VP的历史记录。
这个 History单子实际上是 没错和 Reader一样的。History t a实际上与 Reader t a(与 t -> a相同)相同。
instance Functor (Hypercube intersection) where
fmap f cube = Hypercube (f . get cube)
instance Applicative (Hypercube intersection) where
-- A "pure" Hypercube is one that has the same value at all intersections
pure = Hypercube . const
-- Apply each function in the @ff@ hypercube to its corresponding point
-- in @fx@.
ff <*> fx = Hypercube $ \x -> (get ff x) (get fx x)
一个很好的类比是,Reader r a表示一个带有“孔”的 a,这使您无法知道我们正在讨论的是哪个 a。你只能得到一个实际的 a一旦你提供了一个 r填补的洞。这样的事情太多了。在上面的例子中,“历史”是指在指定时间之前无法计算的值,超立方体是指在指定交集之前无法计算的值,语言表达式是指在提供变量值之前无法计算的值。它也给你一个直觉,为什么 Reader r a是相同的 r -> a,因为这样的函数也是一个直观的 a缺少一个 r。