【问题标题】:Haskell IO Monad in ST MonadST Monad 中的 Haskell IO Monad
【发布时间】:2022-01-21 09:44:09
【问题描述】:

我想我有一个简单的问题,但我无法解决它: 我想创建一个向量,在这个向量上调用 FFI 并返回它。

import qualified Data.Vector.Storable as VS
import qualified Data.Vector.Storable.Mutable as VSM
withCarray :: Int -> (Ptr Float -> IO ()) -> (Vector Float)
withCarray n f = VS.create $ do
  v <- VSM.new n 
  VSM.unsafeWith v f
  return v

现在,VSM.unsafeWith 返回一个 IO,它位于 ST Monad 中。但如果我使用 ioToST 或 liftIO 我会遇到以下问题:

 Couldn't match type ‘s’ with ‘RealWorld’
      ‘s’ is a rigid type variable bound by
        a type expected by the context:
          forall s. ST s (VSM.MVector s Float)
        at src/Interpolation.hs:(60,30)-(63,10)
      Expected type: ST s (VSM.IOVector Float)
        Actual type: ST s (VSM.MVector (PrimState (ST s)) Float)

任何想法,我如何将unsafeWith 转换为正确的 Monad?我看到IO和ST都是Prim-Monad,应该可以转换吧?

【问题讨论】:

  • 您似乎正在寻找的功能是unsafeIOToST。这是否明智在很大程度上取决于您的 FFI 实际在做什么,我现在太困了,甚至无法猜测它在您的代码上下文中是否合理。
  • 基本上,如果“在此向量上调用 FFI”与任何类型的 I/O 一样,那么您不应该这样做。如果它只是在 C 中实现一个纯函数,那么您尝试的可能是合理的。
  • 一般你不能在IOST之间转换。在IO 中,您可以执行任何操作(例如发送电子邮件、发射导弹……),而ST 保证除了改变ST 引用和向量之外不执行任何I/O。如果您确定 FFI 调用除了改变向量之外没有做任何事情(包括从磁盘/网络读取),那么可以使用 unsafeIOToST。调用这样一个不安全的函数会让您有责任验证是否如此。
  • ST monad 故意禁止你做你想做的事情,因为 IO 可以有任意的副作用,而 ST 不应该有任何副作用。如果知道它没有副作用,那么不安全的转换可能是合适的。

标签: haskell monads


【解决方案1】:

对于 FFI 应用程序,通常最简单的方法是根本不用 ST 并在 IO 中做所有事情。如果您必须有一个纯接口(并且您的 FFI 函数实际上是所需的纯接口),您可以调用unsafePerformIO 来提供一个纯接口。

但是,我想我会回避写withCarray,就像你在这里所做的那样。抽象很好,但是通过传递行为不合适的回调很容易意外误用。如果你必须拥有它,至少将它命名为 unsafeWithCarray 并留下一个黑线鳕明确说明在什么情况下它是安全的。

【讨论】:

  • unsafeDupablePerformIO,在适当的时候。这更接近runST。但当然需要格外小心!
猜你喜欢
  • 2011-10-13
  • 2013-08-15
  • 2022-01-22
  • 2019-01-23
  • 1970-01-01
  • 1970-01-01
  • 2012-06-08
  • 1970-01-01
  • 2011-09-29
相关资源
最近更新 更多