制作Monad类的延续monad包装器实例

时间:2015-01-16 00:38:41

标签: class haskell instance monads continuations

我的Foo类型是Cont a a的简单包装。我想让Foo键入Monad类的实例。我试试这个:

import Control.Monad.Cont

newtype Foo a = Foo {unFoo :: Cont a a}

instance Monad Foo where
    return = Foo . return
    Foo inner >>= func = Foo (inner >>= newFunc)
        where newFunc x = (unFoo $ func x)

但我收到了这个错误:

Couldn't match type `a' with `b'
  `a' is a rigid type variable bound by
      the type signature for >>= :: Foo a -> (a -> Foo b) -> Foo b
      at Classes.hs:7:5
  `b' is a rigid type variable bound by
      the type signature for >>= :: Foo a -> (a -> Foo b) -> Foo b
      at Classes.hs:7:5
Expected type: ContT b Data.Functor.Identity.Identity a
  Actual type: Cont a a
In the first argument of `(>>=)', namely `inner'
In the first argument of `Foo', namely `(inner >>= newFunc)'
In the expression: Foo (inner >>= newFunc)

如何正确添加Monad Foo个实例?

1 个答案:

答案 0 :(得分:5)

您无法将Foo变为Monad

首先,我们要指出Foo a是一种精心编写(a -> a) -> a的方式。

runFoo :: Foo a -> ((a -> a) -> a)
runFoo = runCont . unFoo

foo :: ((a -> a) -> a) -> Foo a
foo = Foo . cont

我们只有一种方式可以定义(>>=) :: Foo a -> (a -> Foo b) -> Foo b。我们需要a传递给箭头a -> Foo b。我们唯一拥有a的{​​{1}}是Foo a,相当于(a -> a) -> a。如果我们可以提供a类型的函数,那么它会给我们a -> aid只有a中的一个。id。因此,如何获得instance Monad Foo where return = Foo . return ma >>= f = f (runFoo ma id) 的唯一选择是通过Monad

m >>= return ≡ m

这将导致Foo法律之一counterExample :: Foo Int counterExample = foo (\f -> if f 0 == 1 then 7 else 13) 失败。我们将写一个住在13的反例。

id

计数器示例在传递标识函数7时产生(+1),但在传递后继函数print $ runFoo counterExample id print $ runFoo counterExample (+1) 13 7 时仅产生Monad

counterExample' = counterExample >>= return

由于counterExample法律,>>=应该与id完全相同,但它不可能。 return已将13传递给该函数,且仅counterExample'编辑了结果counterExamplelet counterExample' = counterExample >>= return print $ runFoo counterExample' id print $ runFoo counterExample' (+1) 13 14 并不像>>=那样做。

Monad

由于Foo只有一种可能的实现,并且它不正确,{{1}}没有正确的{{1}}实例。