【发布时间】:2014-06-01 00:52:56
【问题描述】:
我正在寻找一种优雅的方法来解决以下问题。欢迎所有选项,尤其是类型类和 GADT :-)
场景是这样的:存在一种具有类型(字符串和整数)和操作(+、-、++ 和拆分)的小型语言。该语言有两种语法,每种都有自己的解析器。我想编写一个编译器,它可以从语言 X 到语言 Y,或从 Y 到 X。从一个编译到另一个编译是使用其中之一对表达式列表的直接映射:
xToY :: ExpX -> ExpY
yToX :: ExpY -> ExpX
.. 后跟 show,而不是 [ExpY] 或 [ExpX]。这是这两个编译器函数的简单实现,使用普通数据定义和构造函数上的模式匹配:
测试 noddy 编译器:
*编译器> xToY (ArithOpX (EAddX (IntX 2) (IntX 5))) ArithOpY (EAddY (IntY 2) (IntY 5)) *编译器> yToX (StringOpY (ESplitY (StringY "foo") (StringY "bar"))) StringOpX (ESplitX (StringX "foo") (StringX "bar"))所以它起作用了。不幸的是,有很多代码重复,并且明显出现了一种模式。我想采用 Haskell 的一个更优雅的特性来实现 xToY 和 yToX 给出的相同结果。特别是,我正在寻找一种方法来定义构造函数之间的对偶性,例如StringX s 被编译为StringY s,而StringY s 被编译回StringX s。当然有一个很好的方式来表达这一点?此外,案例匹配右侧的嵌套 xToY 和 yToX 调用看起来很脏,例如ArithOpX (EAddX (yToX a) (yToX b))。一定有更好的办法吗?
【问题讨论】:
-
您的
ExpX和ExpY实际上是某种单一类型Exp t,其中t已被某种类型替换以将其标记为用于不同目的。有关标记类型的规范方法,请参见标记包:hackage.haskell.org/package/tagged。 -
为什么不让两个解析器都产生
ExpX类型的值(并且根本不定义ExpY)...?
标签: haskell