重新格式化 Haskell 数据构造函数类型程序并重新格式化
Posted
技术标签:
【中文标题】重新格式化 Haskell 数据构造函数类型程序并重新格式化【英文标题】:Reformatting a Haskell data constructor type program and reformatting it 【发布时间】:2017-03-13 23:19:40 【问题描述】:我们在一个包含以下数据构造函数和类型的 SIMpL.hs 文件中得到代码:
module SImpL where
data AExprT = ALit ValT -- a literal value (an Int)
| AName NameT -- a variable name (a String)
| Add AExprT AExprT -- one arithmetic expression added to another
| Sub AExprT AExprT -- one arithmetic expression subtracted from another
| Mult AExprT AExprT -- one arithmetic expression multiplied by another
deriving (Show,Eq)
data BExprT = BLit Bool -- a literal value (True or False)
| Eq AExprT AExprT -- an equality test between two arithmetic expressions
| Less AExprT AExprT -- a "less than" test between two arithmetic expressions
| Greater AExprT AExprT -- a "greater than" test between two arithmetic expressions
| Not BExprT -- the negation of a boolean expression
| And BExprT BExprT -- the "and" of two boolean expressions
| Or BExprT BExprT -- the "or" of two boolean expressions
deriving (Show,Eq)
type ValT = Integer
type NameT = String
data StmtT = Assign NameT AExprT |
If BExprT StmtT StmtT |
While BExprT StmtT |
Seq [StmtT] -- If the list is empty, this is a statement that does nothing.
deriving (Show,Eq)
If BExprT StmtT StmtT |
While BExprT StmtT |
Seq [StmtT] -- If the list is empty, this is a statement that does nothing.
deriving (Show,Eq)
type ProgT = StmtT
type StateT = [(NameT, ValT)]
我们被要求做这个任务:
编写一个名为 changeName 的函数,它将采用一个 SIMpL 程序(一个 StmtT 类型的值)并返回该程序的副本,其中一个 变量名称已更改。这个函数应该接受三个参数: 两个字符串和一个 SIMpL 程序。字符串代表变量 名字。您的函数应返回包含所有内容的程序副本 第一个字符串的实例被第二个字符串替换。为了 例如,使用类似 Java 的表示法,如果 myProgram 表示这个 程序:
x = 3
y = 14
z = 0
while (x < y)
z = z + x*y
x = x + 1
answer = z + y
changeName "x" "number" myProgram 的结果应该是 该程序的表示:
number = 3
y = 14
z = 0
while (number < y)
z = z + number *y
number = number + 1
answer = z + y
您的 changeName 函数需要为每种类型的 SIMpL 语言中的语句,您将需要一个辅助函数来 更改表达式中变量的名称。
我处理的伪代码如下:
module Assignment3 where
import SImpL
changeName :: String -> String -> StmtT -> StmtT
changeName val1 val2 (Assign NameT AExprT) = ...
changeName val1 val2 (If BExprT StmtT StmtT) = ...
changeName val1 val2 (While BExprT StmtT) = ...
changeName val1 val2 (Seq [StmtT]) = ...
虽然我认为我理解了这一点的基本要点,但我对代码的实际实现很迷茫。例如,如果您运行此代码:
changeName "x" "num" testMyProgram...
testMyProgram 是简单的
Assign "x" (ALit 3)
不知道如何让Haskell返回一行StmtT代码,如:
Assign "num" (ALit 3)
我很确定这是教师希望从说明中得到的。
【问题讨论】:
作为一个脚注...我会不停地看它,如果我真的弄明白了再回来,但我已经盯着这个看了好几个小时了... 【参考方案1】:您需要创建一个解构术语的函数,如果其中一个组件需要替换,请构造一个新术语。
changeNameStmt x y (Assign a b) | x == a = Assign y (changeNameExpr x y b)
| otherwise = Assign a (changeNameExpr x y b)
...
由于Expr
也可能引用变量,因此有必要递归到它并替换那里的所有出现。
changeNameExpr x y (Name n) | x == n = Name y
...
changeNameExpr x y (Add a b) = Add (changeNameExpr x y a) (changeNameExpr x y b)
对语句中涉及的所有类型执行此操作。如果你想要一个多态的changeName
,你可以定义一个类并创建它的类型实例。
【讨论】:
谢谢,我想我了解您的代码和第一个解构部分,但我不确定 changeNameExpr x y b 的作用。您能否详细说明为什么返回 Assign y b 是不够的? 啊,我想我现在明白了,感谢您的澄清。我们是否必须在“changeNameExpr”中包含 Show 和 Eq 案例,因为它们是派生的?changeNameExpr
作为函数不依赖任何东西,因为类型都是具体的,因此存在唯一相关的Eq
(对于String
)。满意后别忘了关闭问题。
当然,这个解决方案对理解项目有很大帮助,非常感谢。以上是关于重新格式化 Haskell 数据构造函数类型程序并重新格式化的主要内容,如果未能解决你的问题,请参考以下文章