首页 > 解决方案 > 哈斯克尔。如何使用 GADT 实现自定义 monad 转换器?

问题描述

我正在尝试通过实现我自己的来了解 monad 转换器。如果我使用,代码会编译,newType DummyT m x y z = DummyT { runDummyT :: m (Dummy x y z) } 但如果我使用 GADT,则不会编译。但是我需要使用 GADT,但它似乎更难。我收到此错误:

Expecting one more argument to ‘m’   
Expected a type, but ‘m’ has kind ‘* -> *’                                              
In the first argument of ‘DummyT’, namely ‘m’                                          
In the first argument of ‘Functor’, namely ‘(DummyT m x y)`

对于 applicative 和 monad 实例,我得到了同样的错误。为什么我会收到此错误?任何帮助表示赞赏。

我的单子:

instance Monad (Dummy x y) where
  return = Return
  (>>=) = Bind

data Dummy x y z where
  Return :: z -> Dummy x y z
  Bind :: Dummy x y z -> (z -> Dummy x y q) -> Dummy x y q

变压器尝试:

instance Monad m => Functor (DummyT m x y) where
  fmap = liftM

instance Monad m => Applicative (DummyT m x y) where
  pure = return
  (<*>) = ap

instance Monad m => Monad (DummyT m x y) where
  return = Return
  (>>=) = Bind

data DummyT m x y z where
  Return :: z -> DummyT m x y z
  Bind :: DummyT m x y z -> (z -> DummyT m x y q) -> DummyT m x y q

标签: haskellmonad-transformers

解决方案


newType DummyT m x y z = DummyT { runDummyT :: m (Dummy x y z) }

m显然是因为* -> *应用于m类型。

data DummyT m x y z where
  Return :: z -> DummyT m x y z
  Bind :: DummyT m x y z -> (z -> DummyT m x y q) -> DummyT m x y q

m未使用,因此 GHC 推断 kind *,因为这是最简单的。也许,它本可以使这种多类型的,但没有。

如果您想要另一种,请明确要求:

data DummyT (m :: * -> *) x y z where
  Return :: z -> DummyT m x y z
  Bind :: DummyT m x y z -> (z -> DummyT m x y q) -> DummyT m x y q

不过,我想知道,如果不在m这里使用是否有意义。


推荐阅读