定义适用的IO

时间:2014-07-17 12:26:16

标签: haskell

假设:

 class (Functor f) => Applicative f where
   pure :: a -> f a 
   (<*>) :: f (a -> b) -> f a -> f b

我尝试实施Applicative IO

-- Learn You a Haskell is the author of all but the last line of code.
instance Applicative IO where
    pure = return
    a <*> b = do
        f <- a -- IO (a -> b)
        x <- b -- IO a. Now we need to apply (a -> b) on 'IO a' to get IO b'
        case f of IO g -> return g x    -- can't pattern match on IO...

这个优秀的answer解释了为什么不能使用IO构造函数。

但我怎样才能完成这个实例?

3 个答案:

答案 0 :(得分:12)

你正确的正轨。使用IO运算符从<- monad中提取值后,将它们应用于函数(f x)并使用{将其包装回IO monad中{1}}功能。

return

当然,这些事情有效,因为m <*> n = do f <- m x <- n return $ f x 已经是IO类型类的实例。

当您Monad f <- m时,(a -> b) f同样,当您执行x <- n时,您会在a中获得x。现在,您只需在x中应用f的值即可。应用它们之后,您可以使用IO函数将它们包装在return构造函数中。 (我更改了变量名称以避免混淆。)

答案 1 :(得分:6)

你很近但你犯了两个错误:

  • 您误解了f的类型。您已使用记号获取计算f的结果a,因此如果a的类型为IO (a -> b),那么f必须类型为a -> b,而您似乎认为f仍然是IO计算。

  • 你写return g x,我认为你的意思是return (g x)。第一个将return应用于两个参数:gx,而第二个参数将return应用于单个参数:g x

简而言之,您可以通过删除案例表达式并return f x来轻松完成实例。

答案 2 :(得分:0)

另请参阅Control.Applicative中的WrappedMonad,特别是其源代码:http://hackage.haskell.org/package/base-4.4.1.0/docs/src/Control-Applicative.html#WrappedMonad

基本上&lt; *&gt; ap是纯粹的回归。