我有一个输入:
[ 8 `div` 2 + 1 .. ] !! 2 : [ 1 .. 3 ]
输出是:
[7,1,2,3]
但是...... Haskell首先计算了什么?
我不知道优先级,7来自哪里?
答案 0 :(得分:9)
你的问题包含两个问题,所以我会尽力简要回答这两个问题。
给定2 + 4 * 3
这样的表达式,Haskell首先计算2+4
然后再乘以3,还是先计算4*3
然后加2?正如您可能已经猜到的那样,4*3
是第一位的。
你怎么知道哪个先来?您查看相关运算符的文档和/或源代码。或者你可以通过实验来解决它。在你的
示例中[ 8 `div` 2 + 1 .. ] !! 2 : [ 1 .. 3 ]
我从经验中知道,如果你把括号放在任何地方,它们会是这样的:
([ ((8 `div` 2) + 1) .. ] !! 2) : [ 1 .. 3 ]
为了正确理解这一点,您需要打开ghci
,然后输入
:info (+)
例如,它会说出
的内容infixl 6 (+)
如果我们也为其他运营商这样做,我们可以为我们建立一个整洁的表。
infixl 7 `div`
infixl 6 +
infixr 5 :
infixl 9 !!
ghci
没有为(!!)
说任何话,但我去了source code for list operations in the Prelude并找到了说明我在表格中显示的内容的行。然后你可以假设列表的工作方式有点像圆括号,所以[]
方括号内的东西都在它们之外的东西之前。
现在,infix
声明中的运算符名称前面的数字表示运算符的优先级越高 - 数字越大,在其他事情之前就越多。在这种情况下,例如,我们有
infixl 7 `div`
infixl 6 +
这意味着`div`
在+
之前,实际上在表达式
8 `div` 2 + 1
我们发现Haskell计算结果为
(8 `div` 2) + 1
因为`div`
具有更高的优先级。如果对表达式的其余部分执行此操作,则最终将使用与此答案开头时相同的括号。
你通常不必非常关心,因为你写的Haskell越多,你就会越了解它是如何运作的。而且大多数情况下,如果你弄错了,你也会得到一个类型错误,提醒你错了。如果有疑问,请同时使用括号,而不是ghci
,并查看哪一个给出了正确的答案。
到目前为止,我已经回答了问题" Haskell如何解释表达式?" 实际计算的顺序是一个完全不同的问题。大多数编程语言首先计算内括号 - Haskell完全相反!
给出表达式
([ ((8 `div` 2) + 1) .. ] !! 2) : [ 1 .. 3 ]
Haskell一开始就把它视为
<something>
然后当你要求价值时,它会呻吟一下并意识到它的意思
<something> : <something>
它会意识到需要进一步计算才能给你一个值,所以它会把它扩展为
(<something> !! <something>) : [ 1 .. 3 ]
(顺便说一下,这些<something>
通常被Haskell人称为 thunks 。)然后它必须更深入,将其转化为
([ <something> .. ] !! 2) : [ 1 .. 3 ]
然后它需要此列表的第二个元素,因此它将扩展尽可能多的列表。
([ <something>
, (<something> + 1)
, (<something> + 2) .. ] !! 2) : [ 1 .. 3 ]
然后它可以减少!!
,返回列表的第三个元素(索引为2),因此整个列表消失并被第三个元素替换。
(<something> + 2) : [ 1 .. 3 ]
然后它可以减少:
,因此结果是一个列表。
[ <something + 2>, 1, 2, 3 ]
此时,它最终必须弄清<something>
是什么,所以它回到它的定义并将其扩展为
[ (<something> + 1) + 2, 1, 2, 3 ]
然后
[ ((8 `div` 2) + 1) + 2, 1, 2, 3 ]
和然后它开始计算第一个元素的实际值,给你
[ (4 + 1) + 2, 1, 2, 3 ]
[ 5 + 2, 1, 2, 3 ]
[ 7, 1, 2, 3 ]
从中可以看出,Haskell试图不计算任何值,除非它绝对必须。它尽可能地尝试仅使用值的描述,而不是任何实际值。它在结束中执行所有必要的计算。
如果您没有要求列表的第一个值,那么永远不会计算。
这是&#34;懒惰评估的意思。&#34;
答案 1 :(得分:4)
[ 8 `div` 2 + 1 .. ] !! 2 : [ 1 .. 3 ]
[ 4 + 1 .. ] !! 2 : [ 1 .. 3 ]
[ 5 .. ] !! 2 : [ 1 .. 3 ]
7 : [ 1 .. 3 ]
[7,1,2,3]
功能应用程序是从左到右。
答案 2 :(得分:2)
8 `div` 2 ≡ 4
,因此[ 8 `div` 2 + 1 .. ]
表示[ 5 .. ]
。这是一个无限列表[5,6,7,8 ..]
。
list !! n
- 从列表中取 n -th元素(从0开始),所以[5 .. ] !! 2 ≡ 7
。