创建haskell IO包装器

时间:2019-02-24 20:11:41

标签: haskell io-monad

在关于FFI的GHC手册部分中,声明程序员可以使用newtype在IO monad周围创建包装器monad,并在调用外来代码时使用它代替IO monad。 (GHC manual

到目前为止,我有:

newtype PGm a = PGm (IO a)
instance Monad PGm where
   (>>=) a b = ...
   (>>)  a b = ...
   return a  = PGm (return a) --I think
   fail a    = PGm (fail a)   --I think

我不知道如何实现(>>=)(>>)

1 个答案:

答案 0 :(得分:7)

您只需解开并重新包装每个操作。困难的部分是弄清楚展开和重新包装的位置:

newtype PGm a = PGm (IO a)
instance Monad PGm where
   (>>=) (PGm a) b = PGm (a >>= (unPGm . b))
     where
       unPGm (PGm x) = x
   (>>)  (PGm a) (PGm b) = a >> b
   return a  = PGm (return a)
   fail a    = PGm (fail a)

但是,这还远远不够,因为Haskell在定义Functor实例之前需要ApplicativeMonad的实例。一个更简单的解决方案是将{-# LANGUAGE GeneralizedNewtypeDeriving #-}放在文件的顶部(或在GHCi中启用:set -XGeneralizedNewtypeDeriving),这使您可以做到这一点;

newtype PGm a = PGm (IO a) deriving (Functor, Applicative, Monad)

想法是,如果启用此扩展,GHC将足够聪明,可以自动从其“基础”实例派生新类型实例。