"数据类型点菜"与嵌套的FreeT变换器

dan*_*iaz 16 monads haskell

在对这个问题的评论中,已经提到嵌套几层FreeT变换器(每个变换器都有不同的仿函数)可以起到与"数据类型单点"方法类似的目的(尽管使用副产品组合了仿函数)这两种方法不同构.

我的问题是:差异在哪里?是否存在一种方法可以处理的情况,而不是另一种方法?他们是否承认不同的口译员?

更新:这是嵌套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  
Run Code Online (Sandbox Code Playgroud)

(通过使用包中的Producers,这个特殊的例子可以更简单pipes,这是一种特殊的免费monad变换器.)

Yel*_*ika 5

我对自己对此的理解并不是100%自信,所以如果有人注意到(公然)错误,请指出.

从可扩展效果开始,该Eff类型基本上是同构的:

data Eff :: [* -> *] -> * -> * where
    Pure :: a -> Eff es a
    Side :: Union es (Eff es a) -> Eff es a
Run Code Online (Sandbox Code Playgroud)

其中Union es aes参数化类型列表的union/sum类型a.与单数据类型的Union重复应用是同构的:+:.总结(!)全部,Eff似乎是数据类型的优化版本.

我们可以得出结论,本文描述的monad变换器和可扩展效应之间的差异适用于此处.特别是,自由monad变换器堆栈不能交错效果,而数据类型单点/可扩展效果可以.