Haskell函数中的括号

时间:2017-02-17 12:46:10

标签: haskell

我只想知道我们如何知道哪些函数需要括号()而哪些函数不需要?例如

replicate 100 (product (map (*3) (zipWith max [1,2,3,4,5] [4,5,6,7,8])))

工作正常。但

replicate 100 (product (map (*3) (zipWith (max [1,2,3,4,5] [4,5,6,7,8]))))

不起作用。这是因为我为zipWith添加了一组括号。在这个小例子中,zipWith和max没有括号,但是复制,产品和地图都有。一般来说,有一种方法可以知道/确定哪些功能需要括号,哪些功能不需要。

2 个答案:

答案 0 :(得分:11)

函数应用程序是左关联的。所以,当你写一个像:

这样的表达式时
f g h x

意思是:

((f g) h) x

zipWith的类型也提供了线索:

zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]

它说zipWith有3个参数:一个函数和两个列表。

当你写:

zipWith (max [1,2,3,4,5] [4,5,6,7,8])

口译员会理解

max [1,2,3,4,5] [4,5,6,7,8]

将是zipWith的第一个参数,类型不正确。请注意zipWith期望两个参数的函数作为其第一个参数,并且正如@Cubic指出的那样,max [1,2,3,4,5] [4,5,6,7,8]将返回最大值 根据通常的词典顺序(类型为[a]),这两个列表之间的某些类型aOrdNum的实例。说,由于您尝试传递类型

的值,因此错误变得明显
(Num a, Ord a) => [a]

其中值为

(a -> b -> c)

预计。

答案 1 :(得分:4)

罗德里戈给出了正确的答案。我只想补充一点,认为某些功能需要括号是错误的,而其他功能则不然。

这就像学校数学一样:

3 * (4+5)

+表达式不需要使用括号,而*表达式通常不需要

在Haskell中,你总是可以在没有括号的情况下离开。无论何时需要将表达式括在括号中,另一种方法是引入本地名称并将其绑定到该表达式,然后使用名称而不是表达式。

在你的例子中:

replicate 100 (product (map (*3) (zipWith max [1,2,3,4,5] [4,5,6,7,8])))

let list1 = product list2
    list2 = map thrice list3
    thrice x = x*3
    list3 = zipWith max [1,2,3,4,5] [4,5,6,7,8]
in replicate 100 list1

事实上,我经常自上而下编写函数:

foo x y z = result
  where
   result = ...
   ...

然而,正如之前所说的,通过使用(.)($),通常可以在没有括号的情况下编写包含函数应用程序的表达式,在这种情况下,从上面自上而下的方法可能过于冗长,以下内容会更清晰(因为新引入的名称没有噪音):

replicate 100
  . product
  . map (*3)
  $ zipWith max [1..5] [4..8]