大多数单子函数需要纯参数并返回一个单子值。但是有一些函数还需要单子参数,例如:
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)
他们似乎都带来了不同的问题,我无法掌握使用自由单子编码此类操作的通用方法。
In both
finally
andforkIO
the problem is that the monadic argument is of a different type than the result. But for free one would need them to be of the same type, asIO a
gets replaced by the type variable of the encoding type, likedata MyFunctor x = Finally x x x
, which would only encodeIO a -> IO a -> IO a
.In From zero to cooperative threads in 33 lines of Haskell code the author uses
Fork next next
to fist implementcFork :: (Monad m) => Thread m Bool cFork = liftF (Fork False True)
and then uses it to implement
fork :: (Monad m) => Thread m a -> Thread m ()
where the input and output have different types. But I don't understand if this was derived using some process or just an ad-hoc idea that works for this particular purpose.
mplus
is in particular confusing: a naive encoding asdata F b = MZero | MPlus b b
distributes over
>>=
and a suggested better implementation is more complicated. And also a native implementation of a freeMonadPlus
was removed from free.In freer it's implemented by adding
data NonDetEff a where MZero :: NonDetEff a MPlus :: NonDetEff Bool
Why is
MPlus
NonDetEff Bool
instead ofNonDetEff a a
? And is there a way how to make it work withFree
, where we need the data type to be a functor, other than using the CoYoneda functor?- For
forkExec
I have no idea how to proceed at all.