电话:555
DIT 440型
HT(高温)2019

函数编程导论
第1周的练习

第一周的练习:Haskell入门

这个excersise集被设计成非常非常温和地介绍Haskell和交互式Haskell解释器GHCi。您需要在您的计算机或学校的计算机上访问正在运行的Haskell系统。

从第2周开始,有计划的练习课,你可以提问并获得帮助。

你应该在一个下午内完成这份文件。这个主要任务是回答如下问题:

问题: 示例问题。

这些问题都有一个建议的答案,你可以单击左侧的问号符号查看。在看之前,试着自己回答问题!

GHCi作为一个简单的计算器

GHCi是一个Haskell解释器,即它是一个评估Haskell表达式。

您可以通过键入以下命令启动GHCi全球温室气体排放指数在终端中。

全球温室气体排放指数
我们将使用这种风格用于您作为GHCi用户必须输入的文本。

当你启动GHCi时,你会看到这样的欢迎信息:

GHCi,版本8.0.1:http://www.haskell.org/ghc/  :? 寻求帮助
现在,我们不关心欢迎消息,但重点放在带有>符号的最后一行。>符号表示GHCi已准备好接收命令。我们将稍后解释单词前奏曲意味着。最简单的可以给GHCi的命令是一个Haskell表达式,给定一个Haskell表达式GHCi将对其进行评估,并将结果写在屏幕上。尝试:
4+5*634
之后,如>符号所示,GHCi准备接受新命令。我们可以随心所欲地重复这种互动。尝试:
4*(8-5)+3153.5/(3+4)*4.52.25正弦1.571
问题: 第一个表达式包含乘法-加法-和减法运算符。这些是按哪个顺序排列的是否应用了运算符?哪些数字是重复的、相加的和减去?
问题: 什么将结果是如果我们去掉第一个括号表达式,即。4*8-5+3?
问题: 按什么顺序第二个表达式中应用的运算符?
当我们给GHCi一个表情,它可能是表达式包含错误。。。尝试:
3+5*<交互式>:1:4:解析错误(可能缩进不正确)
第一个表达式包含语法错误; 乘法没有右操作数运算符(*)。在第二个表达式中,我们试图除以零。识别不同类型的错误并了解其原因会花点时间学习!

更多GHCi命令

我们使用:q命令来完成GHCi会话。
:q离开GHCi。坎德拉04>
所有GHCi命令除了评估表达式以冒号开头以下为:

重新启动GHCi并通过检查尝试回答以下问题欢迎语。

问题: 有哪些GHCi命令?

两个简单示例

问题: 10月20日,英镑的卖出价为12.7775瑞典克朗2008年。那一天1000瑞典克朗能赚多少英镑?
问题: 有些国家的人使用华氏温标。摄氏度(C)相当于32°华氏度(F),增加5°C对应增加华氏度是多少?28摄氏度是多少华氏度?

可编程袖珍计算器

我们已经看到了如何使用GHCi进行简单的计算。但是这个只是开始。为了更进一步,我们需要定义自己的功能。第一个例子是货币换算上述问题。如果我们需要反复将英镑兑换成瑞典克朗我们可以定义一个函数定义一个函数包括许多步骤。

在使用该定义之前,我们必须将其提供给GHCi。虽然可以在GHCi中直接执行此操作,但更有用的是学习如何在一个单独的文件中执行此操作,因为这是我们必须为大型程序执行的操作。
  1. 使用文本编辑器(Vim和Sublime文本是两个流行的跨柏拉图编辑器,linux上的gedit,Windows上的notepad++,Mac上的Atom都是示例)编写函数文件中的定义。完成此操作后,启动编辑器并创建一个包含上述定义的新文件。将此保存到名为的文件不包括1.hs.
  2. 向GHCi发出加载文件的命令
    :l不包括1.hs编译Main(ex1.hs,解释)好的,加载的模块:主。*主菜单>
我们现在可以使用定义:尝试:
1000英镑78.262612345英镑966.151127775英镑10000
问题: 定义将温度(°C)转换为°F的函数。将此函数添加到不包括1.hs。加载文件并测试功能。
问题: 我们现在就来引入一种新的错误。如果一个人写了会发生什么撅嘴10(请注意拼写错误)。如果一个人写下:磅克朗

比较和更复杂的功能

到目前为止,我们已经通过以下形式的方程定义了函数:
名称 参数=包含参数、数字和算术运算。

这并不总是那么容易,考虑以下示例:

一家商店以3.50瑞典克朗/公斤的价格出售土豆大减价,商店为数量超过10kg。
我们想定义计算价格的函数。

让我们调用这个函数价格和参数v(v).
什么时候?v(v)最多10英镑,那么价格是3.50*伏.如果v(v)超过10,价格是35+3*(v-10)(勾选!)等于5+3*v。因此,我们有:

价格(v)=3.5*v,如果v≤10
价格(v)=5+3*v,如果v> 10个
用哈斯克尔怎么写?首先,请注意GHCi可以比较数字。尝试:
3 < 6真的3.5 <= 3False(错误)磅4000>3*100真的
这种比较的结果是真的False(错误)。注意,小于或等于写为<=.现在,我们可以将价格的定义写如下:
价格 :: 双精度 -> 双精度
价格 v(v)
   | v(v) <= 10 = 3.5*v(v)
   | v(v) > 10  = 5+*v(v)
之间的布尔表达式|=被称为警卫。当此函数为应用于特定参数时,GHCi检查来自自上而下,直到找到一个计算结果为真的,之后,表达式的右侧用于计算结果。如果所有警卫评估为False(错误)GHCi发出错误消息。

将此函数加载到GHCi中,并在不同的论据。

问题: 将最后一个定义更改为:
   | v(v) > 11  = 5+*v(v)
将函数应用于9.5、10.5的结果是什么和11.5?
问题: 将函数更改为:
价格 v(v)
   | v(v) <= 11 = 3.5*v(v)
   | v(v) > 10  = 5+*v(v)
现在将函数应用于9.5、10.5的结果是什么和11.5?
我们可以使用关键字否则作为一名后卫真的。所以,如果否则被用作最后的守卫如果没有其他表达式,则使用右侧的表达式guards的评估结果为true。

因此,我们可以写:

价格 :: 双精度 -> 双精度
价格 v(v)
   |v(v) <= 10   = 3.5*v(v)
   |否则 = 5+*v(v)
问题: 出售土豆很成功,这家商店现在的价格是超过20 KG的数量为2.50 SEK/KG(价格相同其他金额)。将函数更改为以计算正确的价格。

否则Haskell关键字?什么是胡瓜说什么?

当一个函数应用于一个简单的参数(如5)时,我们不需要括号。但如果论点是由+8) 需要括号。

价格7.526.25价格1138.5价格(4+8)41
问题: 尝试评估最后一个不带括号的表达式。你能解释一下结果吗?

具有多个参数的函数

函数可以有多个参数。例如,我们定义了一个定义两个数字的平均值的函数:注意,当一个函数有多个参数时,参数是用空格隔开后写的。当该函数应用于参数时,情况也是如此。
平均5 86.5
问题: 定义函数这是三个数字的平均值。GHCi中函数的负载并进行测试。

序曲

一些函数非常频繁地使用,因此在名为前奏曲,这是每次启动GHCi时自动加载。概述定义的功能可以在中找到,例如。,哈斯克尔前奏曲之旅.

为了能够在Haskell中高效地编程,有必要知道前奏曲中有哪些功能可用。在接下来的几周里,你会越来越熟悉他们。

带两个参数的运算符和函数

编写了*、-、+等运算符中缀,这意味着操作员应该之间它的论点。功能通常是书写前缀,表示它们是书写的在的前面他们的论点。

然而,可以通过将函数写在中间来使用中缀`  `. 运算符可以通过写入前缀来使用在括号之间。尝试:

5 `平均`44.54`最大值`(5`最大值`2)5(+) 3 47

整数

前奏提供功能div公司用于整数除法。尝试:
第17 5部分第34 8部分4第5部分904 `div`22
功能国防部给出整数除法的余数:
17 `mod`5234 `mod`825 `mod`95模块4 20
问题: 是什么5 `mod`0?
问题: 107139224能被11731整除吗?
问题: 定义函数给定的一年表示该年的天数。使用了被四整除的年份是闰年的简化规则(年,366天)。您必须使用关系运算符==其计算结果为真的如果它的参数相等。

一个更大的例子

考虑以下游戏:

想想一个大于一的整数。如果是偶数,除以二,否则乘以三加一。如果出现以下情况,请停止结果是1,否则重复该过程。
例如,我们从宽度10开始。

如果我们从7开始,我们会得到:(检查这个!)

7, 22, 11, 34, 17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1.

我们对这个问题感兴趣:给定一个数字n个,有多少序列中有数字吗?对于n个=10,我们得到7个数字(10,5,16, 8, 4, 2, 1). 对于n个=7我们得到17个数字(见上文)。注意,我们包括了这两个数字n个我们从和决赛开始数字1。

GHCi如何帮助我们回答这个问题?我们从定义开始一个函数下一个给定一个数字计算下一个数字在序列中。

问题: 定义函数下一个
问题: n=6的序列长度是多少?
问题: 我们想定义一个函数步骤这需要一个数字n个作为参数并计算生成序列的长度。是什么步骤20? 而且步骤3?
在上一个练习的指导下,我们观察到步骤符合:
步骤 :: 国际 -> 国际
步骤 n个
   | n个 == 1    = 1
   | 否则 = 步骤(下一个 n个)+1
我们称之为递归的定义。(你之前应该已经了解了这个概念,否则就要求退还你的本科教育费用!)在你的文件中写下定义。将其加载到GHCi中,并计算步骤n代表几个不同的n值。

这一切似乎都没有任何问题。但同时也可以想知道:

问题: 你能肯定吗不管你是什么号码,最终你都会达到1号从开始?
最后,我们定义了函数数字计算游戏中生成的实际数字列表:
数字 :: 国际 ->[国际]数字 n个
     | n个==1      =[1]| 否则 = n个 以下为: 数字(下一个 n个)
将函数加载到GHCi并尝试:
数字10[10, 5, 16, 8, 4, 2, 1]数字17[17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1]数字1[1]
研究函数定义:当n=1时,结果是列表[1]. 否则我们使用运算符以下为:,命名为cons,其中通过将元素放置在,从元素和列表构造列表列表的顶部。的结果数字nn个然后是列表数字(下一个n).

现在我们已经定义了函数数字我们不需要定义步骤因为有一个函数长度在计算列表长度的前奏中。

尝试:
长度[1,6,33,8,7,14]6长度(数字10)7