【问题标题】:Create haskell IO wrapper创建 haskell IO 包装器
【发布时间】:2019-07-18 06:11:13
【问题描述】:

在 FFI 的 GHC 手册部分中,指出程序员可以使用newtype 在 IO monad 周围创建一个 wrapper 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

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

【问题讨论】:

    标签: haskell io-monad


    【解决方案1】:

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

    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 需要 FunctorApplicative 的实例,然后才能定义 Monad 实例。更简单的解决方案是将 {-# LANGUAGE GeneralizedNewtypeDeriving #-} 放在文件顶部(或在 GHCi 中启用 :set -XGeneralizedNewtypeDeriving),这样您就可以做到这一点;

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

    我们的想法是,如果您启用此扩展,GHC 将足够智能,可以自动从它们的“基础”实例派生新类型实例。

    【讨论】:

    • 另外,如果使用记录语法将unPGm 放在PGm 的定义中,>>= 会更简单:newtype PGm a = PGm { unPGm :: IO a }
    • @chepner 是的,确实如此,但我决定暂时保留 EdBehn 的定义。我肯定会使用记录语法来定义这种类型。
    • 谢谢。在我发布之后我已经弄清楚了一些,但是你实现 >>= 的方式比我的要干净得多。当然使用派生更干净。
    • @EdBehn 不客气!对于这类事情,我几乎总是使用GeneralizedNewtypeDeriving,除非我需要一些特别的东西。还有plenty other useful extensions - 我强烈建议您看看它们!
    猜你喜欢
    • 2021-03-26
    • 2019-03-28
    • 2019-07-31
    • 1970-01-01
    • 2012-02-19
    • 2012-09-27
    • 1970-01-01
    • 1970-01-01
    • 2011-07-11
    相关资源
    最近更新 更多