1、假设存在一种算术表达式的具体语法,(a) 证明1 - 2 - 3和1 + 2 * 3是该语言中的有效表达式,并列出在算术运算符具有通常语义的情况下它们可能的结果。(b) 1 + (2 - 3)和 - 1是否是该语言中的有效表达式?(c) 使用Haskell计算表达式1 - 2 - 3和1 + 2 * 3。根据得到的结果,你能解释Haskell是如何解析这些表达式的吗?识别每个表达式中的主运算符(即Haskell生成的语法树的根)及其参数。
(a) 这些表达式可以按以下方式生成:
Exp → Exp Op Exp
→ Num Op Exp
→ Digit Op Exp
→ 1 Op Exp
→ 1 - Exp
→ 1 - Exp Op Exp
→ 1 - Num Op Exp
→ 1 - Digit Op Exp
→ 1 - 2 Op Exp
→ 1 - 2 - Exp
→ 1 - 2 - Num
→ 1 - 2 - Digit
→ 1 - 2 - 3
Exp → Exp Op Exp
→ Num Op Exp
→ Digit Op Exp
→ 1 Op Exp
→ 1 + Exp
→ 1 + Exp Op Exp
→ 1 + Num Op Exp
→ 1 + Digit Op Exp
→ 1 + 2 Op Exp
→ 1 + 2 * Exp
→ 1 + 2 * Num
→ 1 + 2 * Digit
→ 1 + 2 * 3
(b) 否,该语法无法生成带有括号或以运算符开头的表达式。
(c) 在 Haskell 中, * 的优先级高于 + ,且优先级相同的运算符左结合。在第一个表达式中,根运算符是最右边的 - ,在第二个表达式中,根运算符是 + 。结果分别为 -4 和 7 。
2、使用指定的算术表达式抽象语法规则来证明:(a) 证明 -( -(1, 2), 3) 和 -(1, -(2, 3)) 都是有效的。假设算术运算符具有通常的语义,它们的值是多少?(b) 解释为什么 -(1, 2, 3) 根据此语法不是有效的抽象语法树。
(a) 为证明它们有效,展示它们可以被生成:
- $ E \rightarrow Op(E, E) \rightarrow -(E, E) \rightarrow - (Op(E, E), E) \rightarrow - (-(E, E), E) \rightarrow - (-(1, E), E) \rightarrow - (-(1, 2), E) \rightarrow - (-(1, 2), 3) $
- $ E \rightarrow Op(E, E) \rightarrow -(E, E) \rightarrow - (1, E) \rightarrow - (1, Op(E, E)) \rightarrow - (1, -(E, E)) \rightarrow - (1, -(2, E)) \rightarrow - (1, -(2, 3)) $
结果分别是 -4 和 2 。
(b) 该语法规定每个运算符有两个参数。
3、假设我们要定义一种语言 L,其中变量标识符是字母或数字的序列,且以大写字母开头。请给出语言 L 中标识符具体语法的文法。
id ::= Cap any
Cap ::= A | B | C | ... | Z
any ::= char | char any
char ::= Cap | small | digit
small ::= a | b | c | ... | z
digit ::= 0 | 1 | 2 | ... | 9
4、以下语法定义了Haskell中标识符的具体语法。非终结符用斜体表示。在第一条规则中,使用特殊符号表示集合差:(small rest)–keywords 表示由 small rest 生成的字符串减去由 keywords 生成的字符串。在第三条规则中,符号 ϵ 表示空字符串。varid →(small rest) − keywords small →a | b | c |… | z rest →ϵ | sldq rest sldq →small | large | digit | ’ large →A | B | C |… | Z digit →0 | 1 | 2 |… | 9 keywords →case | class | data | default | deriving | do | else | if | import | in | infix | infixl | infixr | instance | let | module | newtype | of | then | type | where | _ (a) 用英语解释标识符是如何形成的。(b) 扩展该语法,增加一条规则来指定Haskell中函数声明的形式:decl →let varid args = expr1 in expr2 其中 varid 是函数名,args 是其参数,expr1 是其定义,expr2 是使用该函数的表达式(省略了定义 args、expr1、expr2 的语法规则)。例如,以下是一个名为 double 的函数的有效声明,它有一个参数 x,定义为表达式 2 * x,并用于计算 3 的两倍。let double x = 2 * x in double 3 以下Haskell程序存在语法错误。尝试运行这些程序,并解释它们为什么会产生错误消息。根据给定的语法,识别出错误并提出纠正方法。let Double x = 2 * x in Double 3 let dou?ble x = 2 * x in dou?ble 3 let data = 1 in data + 1。
-
(a)标识符是由字母、数字和引号组成的序列,以小写字母开头,并且不包含关键字。
-
(b)在这些程序中,函数使用的名称不满足语法规定的约束:
- 第一个以大写字母开头,
- 第二个包含问号,
- 第三个使用了保留关键字
data。
纠正方法:
- 第一个将大写字母改为小写;
- 第二个去掉问号;
- 第三个换一个非关键字的名称。
5、证明集合的并集和交集运算具有以下性质:A ∪B = B ∪A,(A ∪B) ∪C = A ∪(B ∪C),A ∪A = A,A ∩B = B ∩A,(A ∩B) ∩C = A ∩(B ∩C),A ∩A = A。
我们可以利用集合相等的定义和逻辑连接词的性质来证明这些性质。下面证明前两个性质(并集的交换律和结合律)。
1. 并集的交换律: $ A \cup B = B \cup A $
根据集合相等的定义,需证明:
- $ A \cup B \subseteq B \cup A $
- $ B \cup A \subseteq A \cup B $
证明第一个包含关系:
设 $

最低0.47元/天 解锁文章
2万+

被折叠的 条评论
为什么被折叠?



