为什么这个美元符号构造不起作用?

时间:2014-01-28 06:44:19

标签: haskell dollar-sign

是的,另一个美元符号问题。对不起... (我使用了搜索功能!)

我的课程功能编程教授告诉我们美元符号 '有点添加一个开头括号,然后在结尾添加一个'(它大致以大致相同的方式描述here)。所以

fibs = 0 : 1 : zipWith (+) fibs $ tail fibs

应该相当于

fibs = 0 : 1 : zipWith (+) fibs (tail fibs)

嗯,事实并非如此。第二件事编译得很好,第一件事就是错误:

jkjj.hs:1:8:
    Couldn't match expected type `[a1] -> [a1]' with actual type `[a0]'
    The first argument of ($) takes one argument,
    but its type `[a0]' has none
    In the expression: 0 : 1 : zipWith (+) fibs $ tail fibs
    In an equation for `fibs':
        fibs = 0 : 1 : zipWith (+) fibs $ tail fibs

fibonacci.hs:1:16:
    Couldn't match expected type `[a0]' with actual type `[a1] -> [a1]'
    In the return type of a call of `zipWith'
    Probable cause: `zipWith' is applied to too few arguments
    In the second argument of `(:)', namely `zipWith (+) fibs'
    In the second argument of `(:)', namely `1 : zipWith (+) fibs'

当然,因为$是一个函数,例如:

fibs = 0 : 1 $ zipWith (+) fibs (tail fibs)

不起作用,所以至少我教授给出的解释是过于简单化了。在写这篇文章时,我试图放置括号,以便错误相同。我得到了:

fibs = (0 : 1 : zipWith (+) fibs) $ tail fibs

fibs =(0:1:zipWith(+)fibs)(尾纤)

它们都给了我完全相同的错误信息(当然除了列号)。为什么是这样? b $ c d相当于(a b)(c d)而不是b(c d)?我认为这都与函数优先级和/或关联性有关,但我不知道具体细节。我不知道你怎么能看到一个函数有什么优先级(除了尝试很多组合),我也找不到谷歌。

我希望有人可以帮我解决这个问题!

3 个答案:

答案 0 :(得分:9)

这是一个优先问题。您在这里有两个中缀运算符:$。作为中缀运算符,:的优先级高于$,因此它的绑定更紧密。你可以在ghci

中询问优先级
>> :i :
data [] a = ... | a : [a]        -- Defined in `GHC.Types`
infixr 5 :

>> :i $
($) :: (a -> b) -> a -> b
infixr 0 $

infixr表示运算符组右侧(表达式a + b + c被解释为a + (b + c)),数字表示优先级(更高=更紧密的绑定)。

此外,您需要知道函数应用程序具有最高优先级(最严格的绑定)。所以在你的两个表达式中,这一个

fibs = 0 : 1 : zipWith (+) fibs (tail fibs)

分组如

fibs = 0 : (1 : (zipWith (+) fibs (tail fibs)))

而这

fibs = 0 : 1 : zipWith (+) fibs $ tail fibs

分组如

fibs = (0 : (1 : (zipWith (+) fibs))) $ (tail fibs)

会给你一个错误,因为$左边的表达式应该是一个函数,但在你的情况下它是一个列表。

答案 1 :(得分:7)

是的,a b $ c d相当于(a b) (c d)。这是因为美元符号不是一个语法结构:它是一个像其他运算符一样的中缀运算符,并且必须遵守相同的规则。只是$应用了一个函数并且非常低的优先级给出了它的行为。

您询问如何查找运算符的优先级。您可以在GHCi中使用:info

ghci> :info $
($) :: (a -> b) -> a -> b   -- Defined in `GHC.Base'
infixr 0 $

注意最后一行。这表明它是优先级为0的右关联运算符。
(优先级从0到9。)

询问关于:的GHCi给出了以下内容:

ghci> :info :
data [] a = ... | a : [a]   -- Defined in `GHC.Types'
infixr 5 :

所以:也是一个右关联运算符,但优先级为5.由于:的优先级高于$,因此它将被归为{{1}左边的操作数。

答案 2 :(得分:3)

对:你已经发现了

a b ! c d $ e f % g h

可以理解为将表达式放在两个边的表达式周围,即

(a b ! c d) (e f % g h)

只要你只使用你可以在标准Haskell中定义的东西:函数和中缀运算符 1 ,这就行了。

当它还考虑ifcase等语法时,它不起作用的地方。特别是,这就是你教授的解释变得更有用的地方, lambdas 在他们的右边是“贪婪的”:

   \x -> f $ a + x

表示\x -> f (a + x),而不是(\x -> f) (a + x)。但是“对双方的支持”仍然有意义,你只是不能加入lambda箭头:

   \x -> f . g $ a + x

表示\x -> (f . g) (a + x),而不是\x -> f . g (a + x)


1 原则上你可以定义一个自定义中缀运算符,其优先级低于$,但这会让人感到困惑。