是的,另一个美元符号问题。对不起... (我使用了搜索功能!)
我的课程功能编程教授告诉我们美元符号 '有点添加一个开头括号,然后在结尾添加一个'(它大致以大致相同的方式描述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)?我认为这都与函数优先级和/或关联性有关,但我不知道具体细节。我不知道你怎么能看到一个函数有什么优先级(除了尝试很多组合),我也找不到谷歌。
我希望有人可以帮我解决这个问题!
答案 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 ,这就行了。
当它还考虑if
,case
等语法时,它不起作用的地方。特别是,这就是你教授的解释变得更有用的地方, 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 原则上你可以定义一个自定义中缀运算符,其优先级低于$
,但这会让人感到困惑。