2017-02-17 104 views
2

我只想知道我们如何知道哪些函数需要括号(),哪些函数不需要?例如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没有括号,但是复制,产品和地图都是这样。一般来说,有一种方法可以知道/找出哪些功能需要括号,哪些功能不需要。

+0

在前者中,'zipWith'应用于3个参数;函数'max'和2个列表。在后者中,它只适用于一个论点;将'max'应用于2个列表的结果。 – pat

+0

在这种情况下,你可以通过明智地使用函数组合来消除大部分的parens:'replicate 100。产品。 map(* 3)$ zipWith max [1,2,3,4,5] [4,5,6,7,8]' – pat

+0

@pat True,但对于找出圆括号的函数不太有帮助 – Cubic

回答

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]类型的返回这两个列表之间的最大 ,对于某些类型的a这是OrdNum的实例。说,因为你是试图通过

类型的值
(Num a, Ord a) => [a] 

其中type

(a -> b -> c) 

的一个预期值,误差变得明显。

+5

可能值得指出的是,虽然你不能使用max [1,2,3,4,5] [4,5,6,7,8]'作为zipWith的第一个参数,但它是一个正确的表达式(给出两个列表中的字典中更大的字母)。 – Cubic

+0

非常感谢您的解释。非常感激。 – Srinivas

+0

@Srinivas:不客气。如果我的答案没问题,请将其标记为对您问题的回答。 –

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] 
+0

非常感谢您的解释。非常感激。 – Srinivas