在this question的评论中,已经提到嵌套多层FreeT变换器(每个变换器都有不同的仿函数)可以实现与"Data types à la carte"方法类似的目的(尽管两种方法不同构,但是使用副产品组合了仿函数本身。
我的问题是:差异在哪里?是否存在一种方法可以处理的情况,而不是另一种方法?他们是否承认不同的口译员?
更新:以下是嵌套FreeT
变换器的简单示例。通过发出日志消息和请求延迟的能力来扩充计算:
import Data.Functor.Identity
import Control.Monad
import Control.Monad.Trans
import Control.Monad.Trans.Free
import Control.Concurrent
type Delay = Int
type DelayT = FreeT ((,) Delay)
delay :: Monad m => Delay -> DelayT m ()
delay t = liftF (t,())
type Message = String
type LogT = FreeT ((,) Message)
emitLog :: Monad m => Message -> LogT m ()
emitLog msg = liftF (msg,())
type Effected = DelayT (LogT Identity)
program :: Effected Char
program = lift (emitLog "foo") >> delay 1000 >> return 'c'
interpret :: Effected a -> IO a
interpret = (iterT $ \(d,a)->threadDelay d >> a)
. hoistFreeT (iterT $ \(m,a)->putStrLn m >> a)
. hoistFreeT (hoistFreeT (return . runIdentity))
main :: IO ()
main = interpret program >>= putChar
(通过使用Producer
包中的pipes
s,这个特殊的例子可以更简单,这是一种特殊的免费monad变换器。)
答案 0 :(得分:5)
我对自己对此的理解并不是100%自信,所以如果有人注意到任何(公然)错误,请指出。
从可扩展效果开始,Eff
类型与...基本同构:
data Eff :: [* -> *] -> * -> * where
Pure :: a -> Eff es a
Side :: Union es (Eff es a) -> Eff es a
其中Union es a
是由es
参数化的类型列表a
的联合/和类型。 Union
与来自单一数据类型的:+:
的重复应用同构。为了总结(!),Eff
似乎是数据类型的优化版本。
我们可以得出结论,本文描述的monad变换器和可扩展效应之间的差异适用于此处。特别是,自由monad变换器堆栈不能交错效果,而数据类型单点/可扩展效果可以。