在Haskell中扩展数据类型 [英] Extending a datatype in Haskell
问题描述
我写了一个评估器,用于最小程序集的语言。
现在,我想扩展该语言以支持一些语法糖,然后我将回编来仅使用原语操作符。理想的是,我不想再次触摸评估模块。
在OO的做事方式中,我认为可以扩展原来的模块,以支持语法糖操作符,在这里提供翻译规则。
除此之外,我只能想到在这两个模块中重写数据类型构造函数他们不会发生名称冲突,并且从那里继续,好像它们是完全不同的东西,但这意味着一些冗余,因为我必须重复(只是用其他名称)操作员的共同点。同样,我认为这里的关键字是扩展。
有没有实现这个功能的方法?
感谢您花时间阅读此问题。 这个问题被Phil Wadler命名为表达问题,用他的话说:
$ b
目标是按大小写定义数据类型,在那里你可以添加新的数据类型和数据类型的新功能,而无需重新编译现有代码,同时保留
静态类型的安全性。
具有可扩展数据类型的解决方案是使用类型类。
举一个例子,假设我们有一个简单的算术语言:
数据Expr =添加Expr Expr | Mult Expr Expr | Const Int
$ b $ run(Const x)= x
run(Add exp1 exp2)= run exp1 + run exp2
run(Mult exp1 exp2)= run exp1 * run exp2
例如
ghci的>运行(Add(Mult(Const 1)(Const 3))(Const 2))
5
如果我们想以可扩展的方式实现它,我们应该切换到类型类型:
class Expr a where
run :: a - > Int
数据Const = Const Int
实例Expr Const其中
run(Const x)= x
data添加ab =添加ab
实例(Expr a,Expr b)=> Expr(Add ab)where
run(Add expr1 expr2)= run expr1 + run expr2
data Mult ab = Mult ab
instance( Expr a,Expr b)=> Expr(Mult ab)其中
run(Mult expr1 expr2)= run expr1 * run expr2
现在让我们扩展语言添加减法:
data Sub ab = Sub ab
instance(Expr a,Expr b)=> Expr(Sub ab)其中
run(Sub expr1 expr2)= run expr1 - run expr2
eg
ghci>运行(Add(Sub(Const 1)(Const 4))(Const 2))
-1
有关此方法的更多信息,以及有关表达问题的更多信息,请查看Ralf Laemmel的视频 1 和 2 。然而,正如评论中注意到的,这个解决方案发生了变化语义。例如,表达式列表不再合法:
[Add(Const 1)(Const 5),Const 6] - 不检查
使用类型签名的副产品的更通用的解决方案在函数式珍珠数据类型点菜。另请参阅Wadler在论文中的评论。
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.
This problem was named "the expression problem" by Phil Wadler, in his words:
The goal is to define a data type by cases, where one can add new cases to the data type and new functions over the data type, without recompiling existing code, and while retaining static type safety.
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:
data Expr = Add Expr Expr | Mult Expr Expr | Const Int
run (Const x) = x
run (Add exp1 exp2) = run exp1 + run exp2
run (Mult exp1 exp2) = run exp1 * run exp2
e.g.
ghci> run (Add (Mult (Const 1) (Const 3)) (Const 2))
5
If we wanted to implement it in an extensible way, we should switch to type classes:
class Expr a where
run :: a -> Int
data Const = Const Int
instance Expr Const where
run (Const x) = x
data Add a b = Add a b
instance (Expr a,Expr b) => Expr (Add a b) where
run (Add expr1 expr2) = run expr1 + run expr2
data Mult a b = Mult a b
instance (Expr a, Expr b) => Expr (Mult a b) where
run (Mult expr1 expr2) = run expr1 * run expr2
Now let's extend the language adding subtractions:
data Sub a b = Sub a b
instance (Expr a, Expr b) => Expr (Sub a b) where
run (Sub expr1 expr2) = run expr1 - run expr2
e.g.
ghci> run (Add (Sub (Const 1) (Const 4)) (Const 2))
-1
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:
[Add (Const 1) (Const 5), Const 6] -- does not typecheck
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.
这篇关于在Haskell中扩展数据类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!