Как красиво оценить вложенные монады StateT и ErrorT?

У меня есть два объявления типа для управляющих структур на разных уровнях программы. Нижний — Agent, StateT с IO возможностями. Второй — еще один StateT с возможностями Agent, а третий (Plan) — ErrorT.

type Agent = StateT AgentState IO
type Plan = ErrorT PlanError (StateT PlanState Agent)

Как лучше всего оценить Plan? Я написал следующий код, но он не очень удобен, потому что есть множество вложенных вызовов runStateT и runErrorT.

foo :: Plan ()
defaultAgentState :: AgentState
runStateT (runStateT (runErrorT foo) (PlanState 0)) defaultAgentState

Есть ли что-то проще/красивее?


person Riccardo T.    schedule 23.02.2012    source источник
comment
Вы можете определить функцию runPlan, поэтому вам нужно будет складывать только один раз, а не каждый раз, когда вы ее вызываете.   -  person Daniel Fischer    schedule 23.02.2012
comment
Но runPlan будет определено точно так же, как мое последнее выражение, объединяющее runStateT и runErrorT, верно? В общем, ярлыка нет. Если у меня есть стек преобразователей монад, чтобы запустить их, мне нужно сложить нужное количество runXyzT. Прошу прощения за, возможно, глупый вопрос, но я совсем новичок в MTL, мне все еще кажется, что это немного сложно.   -  person Riccardo T.    schedule 23.02.2012
comment
Верно. В каком-то месте каждый из runXyzT должен вызываться, и это невозможно. Но достаточно сделать это в одном месте, поэтому, если вы выполняете много Plan, вам не нужно каждый раз явно повторять стек. Кстати, вопрос определенно не глупый.   -  person Daniel Fischer    schedule 23.02.2012
comment
Идеально, большое спасибо! Если вы вставите эти несколько строк вашего комментария в ответ, я приму это.   -  person Riccardo T.    schedule 23.02.2012
comment
Вы также можете написать обертки вокруг функций State, get, put, modify, gets и т. д., чтобы скрыть lift и сделать понятным, когда вы работаете с AgentState по сравнению с PlanState.   -  person pat    schedule 23.02.2012
comment
Я уже сделал это, спасибо @pat :)   -  person Riccardo T.    schedule 24.02.2012


Ответы (1)


Если у вас есть стек монадного преобразователя, каждая из runXyzT функций отдельных преобразователей должна быть вызвана в какой-то момент, к сожалению, быстрого пути нет.

Однако, если вы используете определенный стек более одного раза, стоит определить специальную функцию runMyStack, чтобы беспорядок стека runXyzT появлялся только в одной точке.

person Daniel Fischer    schedule 23.02.2012