11

在下面的代码片段中,您可以看到我在 Haskell 中编写的两个 collat​​z 函数。对于递归应用程序,我在第一个示例 (collat​​z) 中使用了括号来获得正确的优先级。

因为我刚刚学习了 $ 的函数应用程序,所以我尝试使用那个东西重写函数(collat​​z')。但是,我遇到以下错误:

无法将预期类型 `[a]' 与推断类型 `a1 -> [a1]' 匹配 在 `(:)' 的第二个参数中,即 `collat​​z'' 在 `($)' 的第一个参数中,即`n : collat​​z'' 在表达式中:n : collat​​z' $ n `div` 2

collatz :: (Integral a) => a -> [a]

collatz 1 = [1]

collatz n | even n    = n : collatz (n `div` 2)
          | otherwise = n : collatz (n * 3 + 1)

collatz' :: (Integral a) => a -> [a]

collatz' 1 = [1]

collatz' n | even n    = n : collatz' $ n `div` 2
           | otherwise = n : collatz' $ n * 3 + 1

这对我来说很奇怪,这不起作用。所以我尝试了一个类似的例子:

True : [even $ 3 `div` 3]

如果有人可以看看它并告诉我我做错了什么,我将不胜感激。

4

4 回答 4

18

$:然后(以及其他任何东西)具有较低的优先级,因此您的函数解析为

(n : collatz') $ (n `div` 2)

这会导致您的类型错误。的第二个参数:需要一个列表,但您传递的是 collat​​z 函数。

如果您仍然想避免 3n+1 部分周围的括号,您可以执行以下操作

(n:) . collatz' $ n `div` 2
n : (collatz' $ n `div` 2)

虽然这些不一定比原来的更干净。如果您想知道,(n:)第一个示例中的语法糖是\x -> n : x

于 2011-12-04T21:20:19.013 回答
10

由于其他人已经解释了问题所在,我想我会解释你如何自己解决这个问题。(教人钓鱼等等……)

请注意错误消息的这一部分:

在 '($)' 的第一个参数中,即 'n : collat​​z''

这是注意到这是一个优先问题的线索。GHC 告诉您,它n : collatz'被解析为 的第一个参数$,而您期望第一个参数是 just collatz'

此时,我通常会启动 GHCi 并使用以下:info命令检查涉及的优先级:

> :info :
data [] a = ... | a : [a]   -- Defined in GHC.Types
infixr 5 :
> :info $
($) :: (a -> b) -> a -> b   -- Defined in GHC.Base
infixr 0 $

它说 的优先级:是 5,而 的优先级$是 0,这就解释了为什么 的:绑定比$.

于 2011-12-04T22:00:43.840 回答
6

:比 绑定得更牢固$。考虑

Prelude> let f x = [x]
Prelude> 1 : f 2
[1,2]
Prelude> 1 : f $ 2

<interactive>:1:5:
    Couldn't match expected type `[a0]' with actual type `t0 -> [t0]'
    In the second argument of `(:)', namely `f'
    In the expression: 1 : f
    In the expression: 1 : f $ 2

1 : f注意解析器找到的“表达式” ;它看到(1 : f) $ 2而不是1 : (f $ 2)

于 2011-12-04T21:21:15.927 回答
3

正如@missingno 所说,这是一个运算符优先级问题。你可以像这样重写它

collatz' n | even n    = n : (collatz' $ n `div` 2)
           | otherwise = n : (collatz' $ n * 3 + 1)

但这显然对你没有多大帮助,因为你仍然有括号。

于 2011-12-04T21:23:38.277 回答