相同单体变压器的不同排序有何区别? [英] What is the difference between different orderings of the same monad transformers?

查看:133
本文介绍了相同单体变压器的不同排序有何区别?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

  newtype程序a = { runProcedure ::? } 

有状态,包含ID到记录的映射:

 类型ID = Int 
数据记录= {...}
类型ProcedureState =地图ID记录

有三种基本操作:

  abort :: Procedure()
- 从共享状态获取记录;如果记录不存在则中止。
retrieve :: ID - >过程记录
- 以共享状态存储(或覆盖)一条记录。
store :: ID - >记录 - >程序()

这些操作有几个目标:


  • 程序可以假设
    (与原始 Map.lookup 调用不同)是可用的,如果
    的任何假设都是错误的,
    程序整体返回
    失败。
  • 一系列过程可以$ b使用< |> (来自
    class Alternative)将$ b链接在一起,以使
    回落到制作
    的过程不同的假设。 (类似于
    STM's orElse



  • 鉴于这些目标,我相信我需要 State Maybe monad的组合。

       - 选择哪个? 
    类型过程a = StateT ProcedureState可能是
    类型过程a = MaybeT(State过程状态)a

    我无法弄清楚 Maybe State 这两个顺序的行为会有什么不同。 任何人都可以解释两个订单之间的行为差​​异吗?

    另外,如果您发现我原先的想法存在问题(也许我已经完成了

    结论:
    这三个答案都很有帮助,但有一个共同点这个想法帮助我决定了我想要的订单。通过查看返回类型 runMaybeT / runStateT ,很容易看出哪个组合具有我正在寻找的行为对于。 (在我的情况下,我希望返回类型为 Maybe(ProcedureState,a))。

    解决方案< /编辑:我最初得到的情况倒退。现在修好了。



    monad变压器堆栈的顺序之间的差异真的只在您剥离堆栈层时很重要。

     类型过程a = MaybeT(State过程状态)a 

    在这种情况下,您首先运行MaybeT,这会导致有状态的计算,返回也许a

     类型过程a = StateT过程状态可能是

    StateT 是外部monad,这意味着在初始状态下运行StateT之后,您会得到 Maybe(a,ProcedureState) 。也就是说,计算可能已成功,或可能没有。



    所以您选择取决于您想要如何处理部分计算。在外部使用 MaybeT 时,无论计算成功与否,您都会得到某种返回状态,这可能有用也可能没有用。在外部使用 StateT ,可以保证所有有状态事务都是有效的。从你所描述的情况来看,我可能会自己使用 StateT 变体,但我预计两者都可以使用。



    对于monad变压器排序的唯一规则是,如果涉及 IO (或另一个非变压器monad),它必须是堆栈的底部。如果需要,人们通常会使用 ErrorT 作为下一个最低级别。


    I am attempting to define an API to express a particular type of procedure in my program.

    newtype Procedure a = { runProcedure :: ? }
    

    There is state, consisting of a mapping of IDs to records:

    type ID = Int
    data Record = { ... }
    type ProcedureState = Map ID Record
    

    There are three basic operations:

    -- Declare the current procedure invalid and bail (similar to some definitions of fail for class Monad)
    abort :: Procedure ()
    -- Get a record from the shared state; abort if the record does not exist.
    retrieve :: ID -> Procedure Record
    -- Store (or overwrite) a record in the shared state.
    store :: ID -> Record -> Procedure ()
    

    I have a few goals with these operations:

    • Procedures can make assumptions (unlike a raw Map.lookup call) about which records are available, and if any of their assumptions are wrong, the Procedure as a whole returns failure.
    • A series of Procedures can be chained together using <|> (from class Alternative) in order to fall back to Procedures that make different assumptions. (Similar to STM's orElse)

    Given these goals, I believe I want some combination of the State and Maybe monads.

    -- Which to choose?
    type Procedure a = StateT ProcedureState Maybe a
    type Procedure a = MaybeT (State ProcedureState) a
    

    I can't figure out how the two orderings of Maybe and State will behave differently. Can anyone explain the difference in behavior between the two orderings?

    Also, if you see a problem with my original thinking (perhaps I am over-engineering), feel free to point it out.

    Conclusion: All three answers were helpful, but there was one common idea that helped me decide which ordering I wanted. By looking at the return type of runMaybeT/runStateT, it was easy to see which combination had the behavior I was looking for. (In my case, I want the return type Maybe (ProcedureState, a)).

    解决方案

    Edit: I originally got the cases backwards. Fixed now.

    The difference between orderings of monad transformer stacks really only matters when you're peeling off layers of the stack.

    type Procedure a = MaybeT (State ProcedureState) a
    

    In this case, you first run the MaybeT, which results in a stateful computation which returns a Maybe a.

    type Procedure a = StateT ProcedureState Maybe a
    

    Here the StateT is the outer monad, which means that after running the StateT with an initial state, you'll be given a Maybe (a, ProcedureState). That is, the computation may have succeeded, or may not have.

    So which you choose depends upon how you want to handle partial computations. With MaybeT on the outside, you'll always get some sort of returned state regardless of the computation's success, which may or may not be useful. With StateT on the outside, you guarantee that all stateful transactions are valid. From what you describe, I would probably use the StateT variant myself, but I expect either could work.

    The only rule for monad transformer ordering is that if IO (or another non-transformer monad) is involved, it must be the bottom of the stack. Typically people will use ErrorT as the next lowest level if it's required.

    这篇关于相同单体变压器的不同排序有何区别?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆