Class 使[StackExp]成为Expr类的实例
我为算术运算制作classClass 使[StackExp]成为Expr类的实例,class,haskell,instance,Class,Haskell,Instance,我为算术运算制作classExpr class Expr a where mul :: a -> a -> a add :: a -> a -> a lit :: Integer -> a 我想“解析”这样的东西:mul(add(lit3)(lit2))(lit4)=(3+2)*4 我有数据类型: data StackExp = PushI Integer | PushB Bool | Add
Expr
class Expr a where
mul :: a -> a -> a
add :: a -> a -> a
lit :: Integer -> a
我想“解析”这样的东西:mul(add(lit3)(lit2))(lit4)=(3+2)*4
我有数据类型:
data StackExp = PushI Integer
| PushB Bool
| Add
| Mul
| And
| Or
deriving Show
及
我的任务是:我需要为类型Program
更具体地说,我想进行以下转换:
mul(add(lit 3)(lit 2))(lit 4)
->[PushI 2,PushI 3,add,PushI 4,mul]
我遇到了问题,因为我在实例声明的输出中收到了[[StackExp]]
我的尝试:
instance Expr Program where
lit n = (PushI n):[]
add exp1 exp2 = exp1:(exp2:[Add])
mul exp1 exp2 = exp1:(exp2:[Mul])
我不知道如何将所有子表达式连接到列表中
----------------编译器错误如下所示------------------------
Couldn't match type `[StackExp]' with `StackExp'
Expected type: StackExp
Actual type: Program
因此,您基本上要做的是从表达式语言的抽象语法(type class
Expr
)编译为简单堆栈机器的代码(typeStackExpr
的元素列表)
然后您立即遇到的一个问题是,仅在Haskell 98或Haskell 2010中,您无法声明类的实例。例如,GHC将投诉
Illegal instance declaration for `Expr [StackExp]'
(All instance types must be of the form (T a1 ... an)
where a1 ... an are *distinct type variables*,
and each type variable appears at most once in the instance head.
Use -XFlexibleInstances if you want to disable this.)
In the instance declaration for `Expr [StackExp]'
为了解决这个问题,您可以将Program
定义为类型同构(而不是像现在这样仅仅是一个类型同义词):
然后使程序成为类Expr的实例。(或者,您可以根据上面的错误消息建议启用FlexibleInstances
。)
现在我们可以编写所需的实例声明:
instance Expr Program where
mul (P x) (P y) = P (x ++ y ++ [Mul])
add (P x) (P y) = P (x ++ y ++ [Add])
lit n = P [PushI n]
也就是说,对于乘法和加法,我们首先编译操作数,然后分别生成Mul
或Add
指令;对于文本,我们生成相应的push指令
通过这一声明,我们可以得到,例如:
> mul (add (lit 3) (lit 2)) (lit 4) :: Program
P [PushI 3,PushI 2,Add,PushI 4,Mul]
(与您的示例不同。您将操作数的顺序交换为Add
。由于加法是可交换的,因此我假设此版本也是可以接受的。)
当然,为堆栈程序编写一个小型计算器更有趣:
eval :: Program -> [Integer]
eval (P es) = go es []
where
go [] s = s
go (PushI n : es) s = go es (n : s)
go (Add : es) (m : n : s) = go es ((m + n) : s)
go (Mul : es) (m : n : s) = go es ((m * n) : s)
(请注意,我忽略了这里处理布尔值的说明,因为您似乎只处理整数表达式。)
现在我们以你为例
> eval (mul (add (lit 3) (lit 2)) (lit 4))
[20]
这似乎是正确的。对不起,我想我刚刚解决了问题:添加exp1 exp2=exp1++exp2++[add]mul exp1 exp2=exp1++exp2++[mul]如果有效,您可以回答自己的问题,这样这个问题就不会看起来还没有解决。谢谢您的回答。是的,我启用了灵活的实例,因为GHCi编译器建议我这样做=)。
eval :: Program -> [Integer]
eval (P es) = go es []
where
go [] s = s
go (PushI n : es) s = go es (n : s)
go (Add : es) (m : n : s) = go es ((m + n) : s)
go (Mul : es) (m : n : s) = go es ((m * n) : s)
> eval (mul (add (lit 3) (lit 2)) (lit 4))
[20]