首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >互通式变压器中的Monad变压器

互通式变压器中的Monad变压器
EN

Stack Overflow用户
提问于 2022-10-16 12:09:58
回答 1查看 81关注 0票数 2

我在Monad Transformers上遇到了一个问题,但我认为包含一些关于我如何达到当前状态的上下文是有帮助的,所以我首先对我的程序做一个粗略的解释:

该项目是一种简单(玩具)编程语言的解释器。我有一个用来代表评估的单子。它的定义如下:

代码语言:javascript
复制
type Eval a = ReaderT Environment (ExceptT String (State ProgState a))

这很好,我可以很高兴地编写一个评估函数:

代码语言:javascript
复制
eval :: Expr -> Eval Value
eval (Apply l r) = ...
eval ...

值数据类型有点奇怪,我嵌入了Value -> EvalM Value类型的Haskell函数。为此,我在定义中添加了一个泛型类型参数,然后使用EvalM实例化该参数。

代码语言:javascript
复制
data Value' m
  = IntVal Int 
  ...
  | Builtin (Value' m -> m (Value' m))

type Value = Value' EvalM

事情进行得很顺利,但后来我不得不编写一个函数,该函数使用Eval monad和IO操作大量交织代码。这看起来有点可怕:

代码语言:javascript
复制
  case runEval ({-- some computation--}) of 
    Right (val, state') -> do
     result <- -- IO stuff here 
     case runEvaL {-- something involving result --} of 
      ...
    Left err -> ...

该函数有5个层次的嵌套,也是递归的.绝对丑陋:我希望适应使用Monad转换器将是解决方案:

代码语言:javascript
复制
type EvalT m = ReaderT Environment (ExceptT String (StateT ProgState m))

这种重构相对来说是无痛的:它主要涉及更改类型签名,而不是实际的代码,但是存在一个问题:Builtin。给定一个将参数x应用于表单Builtin f的值的表达式,eval函数将简单地返回f x。然而,它有类型Eval Value,但是重构的eval需要有类型签名:

代码语言:javascript
复制
eval :: Monad m => EvalT m Value

至于解决这个问题(即使之成为打字机),我可以想出几个解决方案,每个解决方案都有一个问题:

  1. Implementing类似于lift,在那里我可以带Eval aEvalT m a
    • Problem:我不知道怎么做(如果是possible)

的话)

  1. 更改Value类型,使其由内部monad (即Value m = Value' (EvalT m) )索引。
    • Problem:现在任何包含Value m的东西都必须由m参数化。我觉得这会不必要地扰乱任何包含code.

的类型签名,这是一个问题,考虑到进行此更改的最初动机是清理我的Value

当然,也许有一个更好的解决方案,我还没有想到。如有任何反馈/建议,将不胜感激:)。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-10-16 18:15:35

您可能会喜欢mmorph包。

代码语言:javascript
复制
-- since State s = StateT s Identity, it's probably also the case
-- that Eval = EvalT Identity, under some light assumptions about
-- typos in the question
liftBuiltin :: Monad m => Eval a -> EvalT m a
liftBuiltin = hoist (hoist (hoist generalize))

或者,您可以在值中存储一个多态函数。一种方法是参数化变压器。

代码语言:javascript
复制
data Value' t = ... | Builtin (forall m. Monad m => Value' t -> t m (Value' t)
type Value = Value' EvalT

另一种方法是使用mtl-style约束。

代码语言:javascript
复制
data Value = ... | Builtin (forall m. (MonadReader Environment m, MonadError String m, MonadState ProgState m) => Value -> m Value)

最后这个,虽然冗长,但在我看来相当不错;我可能会从那里开始。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/74086991

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档