【发布时间】: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 中实现一个纯函数,那么您尝试的可能是合理的。
-
一般你不能在
IO和ST之间转换。在IO中,您可以执行任何操作(例如发送电子邮件、发射导弹……),而ST保证除了改变ST引用和向量之外不执行任何I/O。如果您确定 FFI 调用除了改变向量之外没有做任何事情(包括从磁盘/网络读取),那么可以使用unsafeIOToST。调用这样一个不安全的函数会让您有责任验证是否如此。 -
ST monad 故意禁止你做你想做的事情,因为 IO 可以有任意的副作用,而 ST 不应该有任何副作用。如果你知道它没有副作用,那么不安全的转换可能是合适的。