在下面的代码片段中,您可以看到我在Haskell中编写的两个collatz函数。对于递归应用程序,我在第一个示例(collatz)中使用括号来获得正确的优先级。
由于我刚刚用$学习了函数应用程序,我试图用这个东西重写函数(collatz')。但是,我遇到以下错误:
无法匹配预期类型`[a]' 反对推断类型`a1 - > [a1]'在`(:)'的第二个参数中,即``collatz''在`($)'的第一个参数中,即`n: collatz''在表达式中:n:collatz'$ 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]
我很感激,如果有人能看一眼并告诉我我做错了什么。
答案 0 :(得分:18)
$
的优先级低于:
(以及其他任何内容),因此您的函数正在解析为
(n : collatz') $ (n `div` 2)
这会导致您的类型错误。 :
的第二个参数需要一个列表,但你要传递的是collatz函数。
如果您仍想避开3n + 1部分的括号,可以执行以下操作
(n:) . collatz' $ n `div` 2
n : (collatz' $ n `div` 2)
虽然这些不一定比原版更清洁。如果您想知道,第一个示例中的(n:)
是\x -> n : x
的语法糖
答案 1 :(得分:10)
由于其他人已经解释了问题所在,我想我会解释你如何能够自己解决这个问题。 (教一个人钓鱼等等......)
请注意错误消息的这一部分:
在'($)'的第一个参数中,即'n:collatz''
这是发现这是优先问题的线索。 GHC告诉你n : collatz'
被解析为$
的第一个参数,而你期望第一个参数只是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,这解释了为什么:
比$
更严格地绑定“ 。
答案 2 :(得分: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)
。
答案 3 :(得分:3)
正如@missingno所说,这是一个运营商优先问题。你可以像这样重写它
collatz' n | even n = n : (collatz' $ n `div` 2)
| otherwise = n : (collatz' $ n * 3 + 1)
但这显然不会给你太多,因为你还有括号。