Haskell:带有$的函数应用程序

时间:2011-12-04 21:15:23

标签: haskell ghci

在下面的代码片段中,您可以看到我在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 个答案:

答案 0 :(得分:18)

$的优先级低于:(以及其他任何内容),因此您的函数正在解析为

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

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

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

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

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

答案 1 :(得分:10)

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

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

  

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

这是发现这是优先问题的线索。 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)

但这显然不会给你太多,因为你还有括号。