TDA 452型
DIT迪特142
2016年HT

2016年功能编程
第5周的练习

第5周练习:递归数据类型

以下是一些练习,旨在帮助您使用递归数据类型。

如果你没有时间做所有这些练习,不要担心。这些练习旨在提供足够的练习,以保持经验丰富的学生很忙。如果你做了所有标有(*)的练习可能理解了本周的内容。

祝你好运!

0 (*). 表达式树和整数树

表达式

从汤普森的书中,阅读第14章第14.2至14.4节。或者,您可以查看数据类型Expr公司对于包含变量的表达式讲座:ExprVar.hs指数.

除此之外,这本书还引入了一种数据类型Expr公司

数据Expr=Lit Int|添加Expr Expr|子Expr Expr
这与我在讲座中使用的类型类似。给定一个表达式,我们想对其求值使用评估由定义
评估::Expr->Inteval(Lit n)=neval(添加e1 e2)=eval e1+eval e2eval(子e1 e2)=eval e1-eval e2
我们还希望能够显示表达式
showExpr::Expr->字符串showExpr(点亮n)=显示nshowExpr(添加e1 e2)=“(”++showExpr e1++“+”++showExpr e2++“)”showExpr(Sub e1 e2)=“(”++showExpr e1++“-”++showExpr e2++“)”

答:。计算

评估(Lit 67)eval(加(减(减(升3)(升1))(降3))showExpr(加(亮67)(亮(-34))

B(*)。定义函数

大小::Expr->Int
计算表达式中运算符的数量。

C(*)。将乘法和整数运算相加按类型划分Expr公司,并重新定义功能评估,显示Expr、和大小包括新案例。你的评估你什么时候做除以零?编写的一个版本评估结果是类型也许是Int.

D。而不是向Expr公司数据类型如中所示C类可以考虑定义

数据Expr=Lit Int|运营运营费用支出data Ops=Add|Sub|Mul|Div
展示功能评估,显示Expr,大小是为此类型定义的。你会如何添加另一个额外操作国防部对于整数的余数划分?

E.公司。在Haskell中,反引号允许我们在中缀形式(实际上是任何函数),类似于(亮3)`添加`(亮15)。但是,如果显示此表达式(使用派生Show)它出现在前缀中格式为加(亮3)(亮15).

也可以对构造函数名称使用中缀运算符,其中第一个字符必须是':'我们可以,例如。,重新定义Expr公司作为

数据Expr=Lit Int|有效期:+:有效期|导出:-:导出
使用此数据类型和infix构造函数重新定义上述函数。

整数树

A类整数树为零或通过组合值和两个子树。在Haskell中,我们可以引入整数树NTree公司通过
数据NTree=NilT|节点Int树NTree
我们可以对节点求和并计算树的深度,如下所示
sumTree::NTree->IntsumTree NilT=0sumTree(节点n t1 t2)=n+sumTreet t1+sumTree t2深度::NTree->Int深度NilT=0深度(节点n t1 t2)=1+最大值(深度t1)(深度t2)

答:。计算

sumTree(节点3(节点4为零)为零深度(节点3(节点4为零)为零

B(*)。定义函数以返回左侧和右侧的子树NTree公司.

C(*)。定义一个函数以确定数字是否为元素NTree公司.

D。定义函数以查找最大值和最小值持有于NTree公司.

E(*)。树通过左右交换反映出来子树,递归。定义要反映的函数一个NTree公司.两次反射的结果是什么?编写一个QuickCheck属性!

(为了能够测试您的属性,您必须制作NTree公司任意的实例。)

F、。定义函数

折叠,排序::NTree->[Int]
把树变成列表。功能崩溃应该枚举左子树,然后枚举节点处的值,最后枚举右子树;分类应该对元素进行排序升序。例如,
塌陷(节点3(节点4无T无T)无T)=[4,3]排序(节点3(节点4无T无T)无T)=[3,4]
为函数编写合适的QuickCheck属性!

1 (*). 文件系统

A类文件包含数据或是目录。A类目录包含其他文件(本身可能是目录)每个人都有一个名字。

答:。设计一个数据类型来表示目录的内容。忽略文件内容:您是只是试图表示文件名和它们的方式组织到这里的目录中。

B。定义一个函数以在目录。您应该返回指向文件的路径名字。因此,如果您的目录包含a、b和c,并且b是包含x和y的目录,然后搜索x应该生成b/x。

2.命题逻辑练习

A类命题是以下值之一的布尔公式形式:

其中p和q是命题。例如,p | ~ p是一个命题。

答:。设计数据类型道具表示命题。

B。定义函数

变量::Prop->[String]

它返回命题中的变量列表。制造商确保每个变量在返回的列表中只出现一次。

假设给您一个变量名列表及其例如,Bool类型的值,[(“p”,正确),(“q”,错误)].定义函数

trueValue::Prop->[(String,Bool)]->Bool
变量具有给定的值。

C、。定义函数

同义反复::Prop->Bool

它返回真的如果这个命题适用于其中出现的变量。

祝贺 你!您已经实现了一个简单的定理证明器。

3 (*). 讲座中关于Expr类型的练习

查看数据类型Expr公司对于带有变量的表达式来自讲座:ExprVar.hs指数.

在讲座中,我展示了一个用于区分表达式的函数,称为差异(瑞典语:“derivera”)。

差异::表达式->名称->表达式diff(数字n)x=数字0diff(相加a b)x=相加(diff a x)(diff b x)diff(Mul a b)x=相加(Mul a(diff b x))(Mul b(diff a x))差异(变化)x|x==y=数字1|否则=数字0

答:。定义一个属性,检查对于每个表达式e,e的导数到x的变量不超过e。

相反的情况也成立吗?

的结果差异函数通常包含以下表达式可以大大简化。

B。(*)定义函数简化给定表达式e,创建一个与e等效但经过简化的表达式。以下示例您可以进行以下简化:

你可以决定你想成为多么雄心勃勃的人!

我们在文件中为您做了一个小的开始ExprVar.hs指数

提示:这个练习更具开放性。

您可以尝试定义简化递归地。然而,你会注意,很难实现许多简化。看一看函数协会会员在汤普森的书中的第14章:

关联::Expr->Exprassoc(添加(添加e1 e2)e3)=assocassoc(添加e1 e2)=添加(assoc e1)(assoce 2)assoc(Sub e1 e2)=Sub(assoc e1)(assoc e2)assoc(升n)=升n

(一种不同但更雄心勃勃的方法是设计一种新型表示标准形例如,对于表达式多项式。您的简化函数可以简单地转换表达式转换为多项式,然后再次转换为表达式。你会怎么做在Haskell中将多变量上的多项式建模为一种类型?)

请确保以下属性适用于您的简化功能:对于每个表达式e,在环境中对其求值会生成简化前后的结果相同:

prop_SimplefyCorrect::Expr->Env->属性prop_SimplefyCorrect e(环境-环境)=eval env e===eval env(简化e)

C、。定义属性:

prop_SimplifyNoJunk::导出->布尔
它检查简化的结果是否“留下任何垃圾”。换句话说,例如,简化的结果应该没有表单的子表达式:等等。什么是允许的“垃圾”,什么不是当然取决于你的简化函数,以及你对它的期望。

此属性归结为定义函数无垃圾::Expr->Bool.我们已经为您在ExprVar.hs指数.

D。定义属性:

prop_SimplefyDiff::Expr->Bool
检查区分表达式然后对其进行简化是否应该其结果与先简化,然后推导,然后简化。

你希望它能保持住吗?它真的支持你的简化功能吗?