如何将逻辑符号转换为Haskell语法

如何将逻辑符号转换为Haskell语法,haskell,functional-programming,Haskell,Functional Programming,我最近在大学学习了Haskell,我正在做一系列练习,下面是一个我无法理解的小片段: 对于简单的前缀计算器语言,请考虑以下语法: 我对如何将其翻译成Haskell语法感到困惑(我是Haskell和函数式编程的完全初学者,请温柔一点) 我怀疑num、int和expr都是可以使用data或type声明的类型/值,它们会对计算器施加约束。但是,我无法理解这两种情况:如何为固定值(即0-9)声明type或data(不是变量)?另外,我如何在声明中放置-或+等符号?不要将语法中的字符串与表示它的AST混淆

我最近在大学学习了Haskell,我正在做一系列练习,下面是一个我无法理解的小片段:

对于简单的前缀计算器语言,请考虑以下语法:

我对如何将其翻译成Haskell语法感到困惑(我是Haskell和函数式编程的完全初学者,请温柔一点)


我怀疑
num
int
expr
都是可以使用
data
type
声明的类型/值,它们会对计算器施加约束。但是,我无法理解这两种情况:如何为固定值(即0-9)声明
type
data
(不是变量)?另外,我如何在声明中放置
-
+
等符号?

不要将语法中的字符串与表示它的AST混淆。比较字符串

"+ + 3 4 5"
这是语法中的一个字符串

Plus (Plus (Literal 3) (Literal 4)) (Literal 5)

这将是AST的一个合理的Haskell值,
String
可以解析到该值。

不要将语法中的字符串与表示它的AST混淆。比较字符串

"+ + 3 4 5"
这是语法中的一个字符串

Plus (Plus (Literal 3) (Literal 4)) (Literal 5)

这对于AST来说是一个合理的Haskell值,
String
可以解析为它。

如果它只是一个关于数据建模的练习(没有代码),那么答案包括将构造函数名称添加到语法中(并将文本数更改为名称)。差不多

data Num = Zero | One | Two | Three | Four | Five 
         | Six | Seven | Eight | Nine
data Int = Single Num | Multiple Num Int
data Exp = ExpInt Int | ExpMinus Exp Exp | ExpMul Exp Exp
         | ExpMul Exp Exp

因此,您可以编写所有类型的代码来解析和计算表达式。

如果这只是一个关于数据建模的练习(没有代码),那么答案包括将构造函数名称添加到语法中(并将文本数更改为名称)。差不多

data Num = Zero | One | Two | Three | Four | Five 
         | Six | Seven | Eight | Nine
data Int = Single Num | Multiple Num Int
data Exp = ExpInt Int | ExpMinus Exp Exp | ExpMul Exp Exp
         | ExpMul Exp Exp
由此,您可以编写所有类型的代码来解析和计算表达式

如何为固定值(即0-9)声明类型或数据(不是变量)

您可以定义一个类型,如

data Digit = Zero | One | Two | Three | Four | Five | Six | Seven | Eight | Nine deriving (Eq, Show)
这表示问题中的
num
。显然,我们不能使用
0,1,2,3,…
,因为它们在Haskell中已经被解释为数字

然后,您可以定义

data Number = Single Digit | Many Digit Number deriving (Eq, Show)
这相当于您的问题中的
int
。此类型表示一个(
单个…
)或多个(
多个…
)数字,它们一起构成一个十进制数。例如,对于这些数据类型,数字361将是
多个三(多个六(单个一))

另外,我如何在声明中放置像-或+这样的符号

无法将这些符号放入类型或数据声明中。但是,您可以为操作使用名称,如
Sum
Sub
Mul
。然后,问题语法的
expr
将转换为

data Expr   = Lit Number
            | Sub Expr Expr
            | Sum Expr Expr
            | Mul Expr Expr
            deriving (Eq, Show)
如果我们有一个字符串
“+((2 5)(1 3))3”
,它表示问题的前缀计算器语言中的一个表达式,它将被解析为
总和(Sub(Lit(Many Two(Single Five)))(Lit(Many One(Single Three)))(Single Three)

如何为固定值(即0-9)声明类型或数据(不是变量)

您可以定义一个类型,如

data Digit = Zero | One | Two | Three | Four | Five | Six | Seven | Eight | Nine deriving (Eq, Show)
这表示问题中的
num
。显然,我们不能使用
0,1,2,3,…
,因为它们在Haskell中已经被解释为数字

然后,您可以定义

data Number = Single Digit | Many Digit Number deriving (Eq, Show)
这相当于您的问题中的
int
。此类型表示一个(
单个…
)或多个(
多个…
)数字,它们一起构成一个十进制数。例如,对于这些数据类型,数字361将是
多个三(多个六(单个一))

另外,我如何在声明中放置像-或+这样的符号

无法将这些符号放入类型或数据声明中。但是,您可以为操作使用名称,如
Sum
Sub
Mul
。然后,问题语法的
expr
将转换为

data Expr   = Lit Number
            | Sub Expr Expr
            | Sum Expr Expr
            | Mul Expr Expr
            deriving (Eq, Show)

如果我们有一个字符串
“+((2 5)(1 3))3”
,它代表你问题的前缀计算器语言中的一个表达式,它将被解析为
和(Sub(Lit(Many-Two(Single-Five)))(Lit(Many-One(Single-Three))(Single-Three)
几年前,我变得聪明了,我将AST类型声明为
Num
Eq
Ord
实例,然后定义AST表达式的数学和比较运算符,以便
expr1+expr2
将生成有效的AST。使用sevenj的声明,可以像
(+)xy=sumxy
那样编写,其中右侧是AST表达式的构造函数。为简洁起见,
one=Lit-one
two=Lit-two
。然后您可以编写
one+one==two
,操作符将生成具有正确优先级的AST。在这和滥用
let{…}in…
语法以允许任意缩进之间,我有一种编写AST的方法,它几乎就是玩具命令式语言本身,上面、下面和左边都有一些样板


不过,助教给我的作业评分时并不觉得有趣,他写道:“这不是哈斯克尔!”

几年前,我变得聪明了,我宣布我的AST类型是
Num
Eq
Ord
实例,然后定义了AST表达式的数学和比较运算符,因此,
expr1+expr2
将生成有效的AST。使用sevenj的声明,可以像
(+)xy=sumxy
那样编写,其中右侧是AST表达式的构造函数。为简洁起见,
one=Lit-one
two=Lit-two
。然后您可以编写
one+one==two
,操作符将使用正确的prec生成AST