我不确定如何科学地准确地提出这个问题,所以我只想给你举个例子。
我在StateT
变换器中使用状态。基础是IO
。在StateT IO
操作中,我需要使用alloca
。但是,我无法将alloca
提升为StateT IO
,因为它需要(Ptr a -> IO a)
类型的参数,而我需要使用(Ptr a -> StateT IO MyState a)
的参数。
(但是,这是关于monad变换器的一般性问题,而不是特定于IO
,StateT
或alloca
。)
我提出了以下工作解决方案:
-- for reference
-- alloca :: (Storable a) => (Ptr a -> IO b) -> IO b
allocaS :: (Storable a) => (Ptr a -> StateT s IO b) -> StateT s IO b
allocaS f = do
state <- get
(res, st) <- liftIO $ alloca $ \ptr -> (runStateT (f ptr) state)
put st
return res
但是,我似乎不应该去除StateT
动作并重新构建alloca
动作,以便与StateT
一起使用。此外,我在一些变体中不止一次地看到过这种模式,并不像{{1}}那样简单安全。
有更好的方法吗?
答案 0 :(得分:4)
这可以使用MonadBaseControl
中的monad-control来完成,What is MonadBaseControl for?完全是出于此目的而设计的:
{-# LANGUAGE FlexibleContexts #-}
import Control.Monad
import Control.Monad.Trans.Control
import qualified Foreign.Ptr as F
import qualified Foreign.Marshal.Alloc as F
import qualified Foreign.Storable as F
alloca :: (MonadBaseControl IO m, F.Storable a) => (F.Ptr a -> m b) -> m b
alloca f = control $ \runInIO -> F.alloca (runInIO . f)
alloca
的此增强版可以与基于实现IO
的{{1}}的任何monad堆栈一起使用,包括MonadBaseControl
。
StateT s IO
实例允许将monadic值编码在基本monad(此处为MonadBaseControl
)中,传递给基本monad中的函数(如IO
),然后重构它们回来。
包{{3}}包含许多提升到F.alloca
的标准IO
功能,但MonadBaseControl IO
尚未包含在其中。
答案 1 :(得分:1)
下午好,
AFAIK,没有将(a -> m b) -> m b
类型的函数转换为(a -> t m b) -> t m b
的一般方法,因为这意味着存在类型为MonadTrans t => (a -> t m b) -> (a -> m b)
的函数。
这样的功能不可能存在,因为大多数变形金刚都不能从类型签名中轻易剥离(如何将MaybeT m a
变为m a
所有a
?)。因此,将(a -> m b) -> m b
变为(a -> t m b) -> t m b
的最常用方法是undefined
。
在StateT s m
的情况下,有一个漏洞允许您无论如何定义它。自StateT s m a === s -> m (s,a)
起,我们可以将类型等式重写为:
(a -> StateT s m b) -> StateT s m b
=== (a -> s -> m (s,b)) -> s -> m (s,b)
=== s -> (s -> (a -> m (s,b)) -> m (s,b) -- we reorder curried arguments
=== s -> (s -> (A -> m B)) -> m B -- where A = a, B = (s,b)
现在解决这个新类型的签名是微不足道的:
liftedState f s run = f (run s)
allocaS :: Storable a => (Ptr a -> StateT IO b) -> StateT IO b
allocaS = isomorphic (liftedState alloca)
这就是我们在代码重用方面所做的最好的事情,而不是为所有表现出相同行为的monad定义MonadTrans的新子类。
我希望自己足够清楚(因为害怕混淆,我不想详细说明)
度过美好的一天: - )