2

我有一个输入:

 [ 8 `div` 2 + 1 .. ] !! 2 : [ 1 .. 3 ]

输出是:

 [7,1,2,3]

但是.. Haskell 首先计算什么?

我不知道优先级,7从哪里来?

4

3 回答 3

9

您的问题包含两个问题,所以我会尽力简要回答这两个问题。

1. Haskell 中的操作顺序

给定一个表达式,例如2 + 4 * 3,Haskell 会2+4先计算然后将其乘以三,还是会在此4*3之前计算然后加二?正如您可能已经猜到的那样,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没有说什么(!!),但是我去前奏中的列表操作的源代码,找到了与我在表中显示的内容完全一致的行。然后你可以假设列表有点像括号,所以[]方括号内的东西在它们之外的东西之前。

优先级如何工作

现在,infix声明中操作符名称前的数字表示操作符的优先级有多高——数字越高,它越在其他事物之前。例如,在这种情况下,我们有

infixl 7 `div`
infixl 6 +

这意味着`div`在 之前+,实际上,在表达式中

8 `div` 2 + 1

我们发现 Haskell 将结果计算为

(8 `div` 2) + 1

因为`div`有更高的优先级。如果您对表达式的其余部分执行此操作,您将得到与我在此答案开头所做的相同的括号。

不过你通常不必太在意,因为你写的 Haskell 越多,你就越能感觉到它是如何运作的。大多数情况下,如果你弄错了,你也会得到一个类型错误来提醒你你弄错了。如有疑问,请尝试带括号和不带括号,ghci看看哪一个给出正确答案。

2. Haskell中的计算顺序

到目前为止,我已经回答了“Haskell 如何解释表达式?”这个问题。实际计算的顺序是一个完全不同的问题。大多数编程语言首先计算内括号——Haskell 恰恰相反!

给定表达式

([ ((8 `div` 2) + 1) .. ] !! 2) : [ 1 .. 3 ]

Haskell 一开始只会将其视为

<something>

然后当你要求价值时,它会呻吟一点,意识到它在说

<something> : <something>

它会意识到它需要进一步计算才能给你一个值,所以它会把它扩展成

(<something> !! <something>) : [ 1 .. 3 ]

(顺便说一句,这些<something>s 通常被 Haskell 人称为thunk。)然后它必须更深入,把它变成

([ <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 试图计算任何值,除非它绝对必须这样做。它尽可能地尝试只处理值的描述,而不是任何实际值。它最终会执行所有必要的计算。

如果你不要求列表的第一个值,它永远不会被计算出来

这就是“惰性评估”的含义。

于 2013-10-30T09:11:06.773 回答
4
[ 8 `div` 2 + 1 .. ] !! 2 : [ 1 .. 3 ]
[ 4 + 1 .. ] !! 2 : [ 1 .. 3 ]
[ 5 .. ] !! 2 : [ 1 .. 3 ]
7 : [ 1 .. 3 ]
[7,1,2,3]

函数应用从左到右。

于 2013-10-30T08:31:20.237 回答
2

8 `div` 2 ≡ 4,所以[ 8 `div` 2 + 1 .. ]意思[ 5 .. ]。这是一个无限列表[5,6,7,8 ..]

list !! n– 从列表中取出第n个元素(从 0 开始),所以[5 .. ] !! 2 ≡ 7.

于 2013-10-30T08:36:48.873 回答