Haskell点运算符

15

我想在Haskell中开发一个简单的平均函数。 这似乎可以工作:

lst = [1, 3]

x = fromIntegral (sum lst)
y = fromIntegral(length lst)

z = x / y

但是为什么下面的版本不起作用呢?

lst = [1, 3]

x = fromIntegral.sum lst
y = fromIntegral.length lst

z = x / y

1
既然你正在计算平均数,请查看 https://dev59.com/kXE95IYBdhLWcg3wSb7P#2380437。 - kennytm
3个回答

17

.(组合)的优先级低于函数应用,因此

fromIntegral.sum lst

被解释为

fromIntegral . (sum lst)

这是错误的,因为sum lst不是一个函数。


17
你被Haskell的操作符优先级规则绊住了,这些规则很容易令人困惑。
当你写下:
x = fromIntegral.sum lst
Haskell认为这与以下内容相同:
x = fromIntegral.(sum lst)

你原本想写的是:

x = (fromIntegral.sum) lst

8
没错。但我认为在操作符两边不加空格有时会导致误解(例如,这看起来类似于许多面向对象编程语言中成员访问的构造)。(fromIntegral . sum) 可能会引起问题,但不会导致误解。 - ony
1
说实话,让人困惑的不是 Haskell 自身的优先级规则(这些规则很容易说明),而是在 Prelude 中定义的令初学者感到困惑的各种运算符以及它们各自的优先级。 - sigfpe

11

我只是想添加“美元来解救!”:

x = fromIntegral $ sum lst
y = fromIntegral $ length lst

它具有最低的优先级,它存在是为了避免太多的括号层次。请注意,与(.)不同,它不执行函数组合,而是对右侧的参数进行评估并将其传递给左侧的函数。类型说得清楚:

($) :: (a -> b) -> a -> b
(.) :: (b -> c) -> (a -> b) -> a -> c

1
你还可以写成 x = fromIntegral . sum $ lst,这更接近于 OP 最初尝试的方式。 - yatima2975
说表达式计算参数的右边并不完全准确。计算仍然是惰性的。为了评估参数,您需要使用$! - Chuck
虽然这个解决方案可行,但我认为它不是正确的答案。在我看来,OP 对运算符优先级感到困惑。因此,答案是指出正确的优先级,并指出括号在这里有帮助。而不是引入另一个运算符。 - Martijn
@Martijn:是的,我同意;这就是为什么我在回答中以“我只是想补充”开头。KennyTM和Daniel上面的答案解决了优先级问题,我只是添加了一个额外的信息。我的答案绝对不应该被接受,但把它放在这里也没有坏处。 - sbk

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接