Haskell 如何用自由的(或更自由的)单子对采取一元参数的操作进行编码?
大多数一元函数采用纯参数并返回一元值。但也有一些需要一元论证,例如:Haskell 如何用自由的(或更自由的)单子对采取一元参数的操作进行编码?,haskell,monads,free-monad,monadplus,Haskell,Monads,Free Monad,Monadplus,大多数一元函数采用纯参数并返回一元值。但也有一些需要一元论证,例如: mplus :: (MonadPlus m) => m a -> m a -> m a finally :: IO a -> IO b -> IO a forkIO :: m () -> m ThreadId -- | From Control.Monad.Parallel forkExec :: m a -> m (m a) 它们中的每一个似乎都提出了一个不同的问题,我无法掌
mplus :: (MonadPlus m) => m a -> m a -> m a
finally :: IO a -> IO b -> IO a
forkIO :: m () -> m ThreadId
-- | From Control.Monad.Parallel
forkExec :: m a -> m (m a)
它们中的每一个似乎都提出了一个不同的问题,我无法掌握一种通用的方法,如何使用免费单子对这些动作进行编码。
- 在
和finally
中,问题在于一元参数的类型与结果不同。但是免费的话,我们需要它们是相同的类型,因为forkIO
被编码类型的类型变量替换,比如ioa
,它只编码data MyFunctor x=Finally x x
在本文中,作者使用ioa->ioa->ioa
来首先实现Fork next
cFork :: (Monad m) => Thread m Bool cFork = liftF (Fork False True)
然后用它来实现fork :: (Monad m) => Thread m a -> Thread m ()
cFork :: (Monad m) => Thread m Bool cFork = liftF (Fork False True)
其中输入和输出具有不同的类型。 但我不明白这是否是通过某种过程得出的,或者仅仅是为了这个特殊目的而产生的一个临时想法fork :: (Monad m) => Thread m a -> Thread m ()
尤其令人困惑:一种像mplus
分布在data F b = MZero | MPlus b b
上,a更复杂。也是免费的MonadPlus的本机实现 在中,它通过添加>=
为什么data NonDetEff a where MZero :: NonDetEff a MPlus :: NonDetEff Bool
MPlus
而不是NonDetEff Bool
?有没有一种方法可以让它在NonDetEff a
中工作,我们需要的数据类型是一个函子,而不是使用Free
- 对于
我根本不知道如何继续forkExec
Freer
monad部分。回想一下定义:
data Freer f b where
Pure :: b -> Freer f b
Roll :: f a -> (a -> Freer f b) -> Freer f b
现在
data NonDetEff a where
MZero :: NonDetEff a
MPlus :: NonDetEff Bool
我们可以定义
type NonDetComp = Freer NonDetEff
当Roll
应用于MPlus
时,a
与Bool
统一,第二个参数的类型是Bool->NonDetEff b
,它基本上是一个元组:
tuplify :: (Bool -> a) -> (a, a)
tuplify f = (f True, f False)
untuplify :: (a, a) -> (Bool -> a)
untuplify (x, y) True = x
untuplify (x, y) False = y
例如:
ex :: NonDetComp Int
ex = Roll MPlus $ Pure . untuplify (1, 2)
因此,我们可以为非确定性计算定义一个MonadPlus
实例
instance MonadPlus NonDetComp where
mzero = Roll MZero Pure
a `mplus` b = Roll MPlus $ untuplify (a, b)
并运行它们
run :: NonDetComp a -> [a]
run (Pure x) = [x]
run (Roll MZero f) = []
run (Roll MPlus f) = let (a, b) = tuplify f in run a ++ run b
在我看来,实现不是取决于函数的类型,而是取决于它的语义。“但我不明白这是否是使用某种过程得出的。”我认为这里的“过程”只是对你的领域进行了适当的建模。例如,我认为如果您首先尝试对“最通用”的异常函数(
throw
,catch
?)进行编码,finally
的编码将更加明显。最后,的类型与@user2407038的类型相同。我理解你的意思。但我对“机械地对整个接口进行编码,让解释器担心实现细节”的方法感兴趣。