继续Monad - Int和String

时间:2015-03-10 02:22:05

标签: haskell

The Mother of all Monads文章提供了此代码:

ex3 = do
  a <- return 1
  b <- ContT (\fred -> "escape")
  return $ a+b

然后我可以执行它:

ghci> runContT ex3 show
"escape"

但我不能跑:

ghci> runContT ex3 id

<interactive>:51:14:
    Couldn't match type ‘[Char]’ with ‘Integer’
    Expected type: Integer -> [Char]
      Actual type: Integer -> Integer
    In the second argument of ‘runContT’, namely ‘id’
    In the expression: runContT ex3 id

return $ a+b如何进行类型检查?

runCont ex3 show发生了什么? runCont ex3 id怎么样 - 看起来它不能用Int + [Char] - 但为什么要编译?

1 个答案:

答案 0 :(得分:1)

首先,让我们看看如何定义Cont

data Cont r a = Cont {runCont :: (a -> r) -> r}

如果放大此声明,您将看到Cont包含一个函数,给定函数(a->r)生成r。换句话说,它隐藏了#34;类型a(或r)&#34;内部&#34; runCont。因此Cont (\fred -> "escape")表达式中freddo是一个函数,并被忽略)的存在告诉我们rString,{{1修复整个表达式以返回类型为runCont的值,并且只能为某些String接受a->String类型的函数,我们需要这些函数才能工作进行。

现在让我们看看a是什么样的:

return

注意instance Monad (Cont r) where return x = Cont ($ x) -- given a function, pass x to it (Cont m) >>= f = -- f :: a -> Cont r b, which roughly means -- f :: a -> (b->r) -> r -- which would roughly be Cont (\g -> m (flip f g)) -- notice we pass f to m: f is the stuff that needs -- executing when m needs to; f is continuation of m let h g x = let (Cont n) = f x -- unwrap (b->r)->r in n g in Cont (m . h) -- or Cont (\g -> m (($ g) . runCont . f)), if that's easier to read 的工作原理。如果>>=没有使用传递给它的函数 - 请记住,m可以&#34;隐藏&#34;类型runCont的值直接,不一定是类型r的值 - 然后是&#34;继续&#34; (a)中的fred未被调用,您将观察&#34; escape&#34;。

因此,Cont (\fred -> "escape")表示a <- return 1,显然,a :: Integer并不代表b <- Cont (\_ -> "escape") - 相反,b :: String可以是任何类型 - function {{传递给b的1}}被忽略,因此返回fred的任何函数都可以工作 - 但Cont的类型由表达式的其余部分修复。 String仅表示b - 由于return $ a + bCont String Integer,因此a也被定义为Integer

另外,请注意b中的Integer定义为show表达式的最后一行的延续:它适用于行runCont ex3 show,所以你打算传递do类型的函数,因为return $ a+bInteger -> r,你打算传递a+b类型的函数,因为Integer是由表达式a -> String修复。

然后整个表达式等同于以下内容:

r