为什么变压器是"运行"功能的第一个参数?

Nik*_*kov 8 haskell monad-transformers

我的意思是为什么不是最后一次?

由于这个评估变换器堆栈的惯例,我必须编写一个类似的尴尬之处:

runStateT (runReaderT (runRWST stack r s) r') s'
Run Code Online (Sandbox Code Playgroud)

代替:

runStateT s' $ runReaderT r' $ runRWST r s $ stack
Run Code Online (Sandbox Code Playgroud)

将它与立即结合起来do变得更加尴尬:

let 
  action = do
    liftIO $ putStrLn "Do"
    liftIO $ putStrLn "something"
  in runStateT (runReaderT (runRWST action r s) r') s'
Run Code Online (Sandbox Code Playgroud)

代替:

runStateT s' $ runReaderT r' $ runRWST r s $ do
  liftIO $ putStrLn "Do"
  liftIO $ putStrLn "something"
Run Code Online (Sandbox Code Playgroud)

这有什么动机或这只是一个不幸的约定吗?

顺便说一句,我确实意识到当前的约定使得使用记录语法实现"运行"功能变得容易,但这不能成为一个论据,因为库必须更易于实现的易用性.

dan*_*iaz 4

在 HaskellWiki 的参数顺序条目和 Stack Overflow 问题中有两个关于参数顺序的建议:

根据我使用 Reader/State monad 的经验,在不同环境/状态上调用相同的计算比在同一环境/状态上调用不同的monadic 计算更频繁。当前的参数顺序对此很方便。

另一个原因:读取器/状态一元值的行为非常类似于以环境/初始状态作为参数的函数。在 Haskell 中,函数位于参数之前。

ReaderT为了避免嵌套//变压器的必要性,您可以使用承载全局状态/环境的单个变压器,并使用镜头StateT中的和来适应在更受限的环境中工作的计算。RWSTRWSTzoommagnify