重新格式化 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 数据构造函数类型程序并重新格式化的主要内容,如果未能解决你的问题,请参考以下文章

Haskell - 简单的构造函数比较(?)函数

在 Haskell 中将字符串转换为类型构造函数

将抽象数据类型保存和加载到 json 文件并从游戏中的文件中读取 Haskell

Haskell 在 Scala 中的新类型

为什么我不能在不同的数据类型中重用相同的值构造函数?

来自源的 Haskell 数据模型可视化