在 Haskell 中扩展数据类型
Haskell 新手在这里。
我为一种最小的类似汇编的语言编写了一个评估器。
现在,我想扩展该语言以支持一些语法糖,然后我将编译回仅使用原始运算符。我的想法是我不想再次触摸评估器模块。
我认为,以面向对象的方式做事,可以扩展原始模块以支持语法糖运算符,并在此处提供翻译规则。
除此之外,我只能考虑重写两个模块中的数据类型构造函数,以便它们不会发生名称冲突,并从那里继续,就好像它们是完全不同的东西一样,但这意味着一些冗余,因为我必须重复(只是使用其他名称)操作员的共同点。同样,我认为这里的关键字是扩展。
有没有一种实用的方法可以实现这一点?
感谢您花时间阅读这个问题。
Haskell newbie here.
I wrote an evaluator for a minimal assembly-like language.
Now, I want to extend that language to support some syntactic sugar which, I will then compile back to use only the primitive operators. The ideia is that I do not want to touch the evaluator module again.
In the OO way of doing things, I think, one could extend the original module so to support the syntactic sugar operators, providing here the translation rules.
Other than that, I can only think of rewriting the datatype constructors in both modules so that they would not name-collide, and proceed from there, as if they were complete different things, but that implies some redundancy, for I would have to repeat (just with other names) the operators in common. Again, I think the keyword here is extend.
Is there a functional way of accomplishing this?
Thanks for taking the time to read this question.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
这个问题被 Phil Wadler 命名为“表达问题”,用他的话说:
拥有可扩展数据类型的一种解决方案是使用类型类。
作为一个例子,我们假设我们有一种简单的算术语言:
例如,
如果我们想以可扩展的方式实现它,我们应该切换到类型类:
现在让我们扩展语言添加减法:
例如,
有关此方法的更多信息,请参阅一般的表达问题,查看Ralf Laemmel的视频1 和2。
但是,正如评论中所注意到的,这个解决方案改变了语义。例如,表达式列表不再合法:
函数珍珠 “数据类型点菜”。另请参阅 Wadler 对本文的评论。
This problem was named "the expression problem" by Phil Wadler, in his words:
One solution to have extensible data type is to use type classes.
As an example let's assume we have a simple language for arithmetics:
e.g.
If we wanted to implement it in an extensible way, we should switch to type classes:
Now let's extend the language adding subtractions:
e.g.
For more info on this approach, and in general on the expression problem, check Ralf Laemmel's videos 1 and 2 on Channel 9.
However, as noticed in the comments, this solution changes the semantics. For example lists of expressions are no longer legal:
A more general solution using coproducts of type signatures is presented in the functional pearl "Data types a la carte". See also Wadler's comment on the paper.
你可以使用存在类型来做一些更像OOP的事情:
通过这样做,我们实际上得到了单个可扩展类型,例如,您可以在列表中混合扩展值和基值:
但是,由于我们现在对 Exp 值唯一了解的是它们在某种程度上是 Eval 的成员,因此我们无法进行模式匹配或执行其他任何东西未在类型类中指定。在 OOP 术语中,将 Exp 视为实现 Eval 接口的对象。如果您有一个 ISomethingThatCanBeEvaluated 类型的对象,显然您无法安全地将其转换为更具体的对象;这同样适用于 Exp。
You could do something a bit more OOP-like using existential types:
By doing this, we actually get a single extendable type so you could, for example, mix extended and base values in a list:
However, since the only thing we now can know about Exp values is that they are somehow members of Eval, we can't pattern match or do anything else that isn't specified in the type class. In OOP terms, think of Exp an exp value as an object that implements the Eval interface. If you have an object of type ISomethingThatCanBeEvaluated, obviously you can't safely cast it into something more specific; the same applies to Exp.
语法糖通常由解析器处理;您可以扩展(不是在 OO 继承的意义上)解析器来检测新的构造并将它们转换为您的评估器可以处理的结构类型。
Syntactic sugar is usually handled by a parser; you'd extend (not in the sense of OO inheritance) the parser to detect the new constructs and translate them to the kind of structures that your evaluator can handle.
一个(更简单的)选项是向 AST 添加类型,以区分核心和扩展:
表达式要么是核心,要么是扩展:编译器将确保它仅包含相同类型的子表达式。
原始模块中的函数签名需要使用
Expr Core
(而不仅仅是Expr
)。Desugar函数将具有以下类型签名:
您可能还对论文'生长的树'。
A (simpler) option is to add a type to your AST, to distinguish Core from Extended:
An expression is either Core or Extended: the compiler will ensure that it contains only sub-expressions of the same type.
The function signatures in your original module would need to use
Expr Core
(instead of justExpr
)A Desugar function would have the following type signature:
You may also be interested in the more sophisticated approach described in the paper 'Trees that grow'.