关于Haskell中的($)的混淆:示例其中($)不明显替换括号

mad*_*n54 2 haskell

假设我有数据类型

data Price = Price Double
data Book = Book {title :: String, bookPrice :: Price}
Run Code Online (Sandbox Code Playgroud)

用函数提取数值

priceAsDouble :: Price -> Double
priceAsDouble (Price doubleValue) = doubleValue
Run Code Online (Sandbox Code Playgroud)

现在,我想在图书清单上写一个累加器,例如

go :: Double -> Book -> Double
go acc book = acc + priceAsDouble (bookPrice book)
Run Code Online (Sandbox Code Playgroud)

哪个很好并且编译.

但是,如果我将最后一行更改为

go acc book = acc + priceAsDouble $ bookPrice book
Run Code Online (Sandbox Code Playgroud)

我得到以下矛盾的编译器错误:

<interactive>:10:51:
Couldn't match expected type ‘Price -> Double’
            with actual type ‘Double’
The first argument of ($) takes one argument,
but its type ‘Double’ has none
In the expression: acc + priceAsDouble $ bookPrice book
In an equation for ‘go’:
    go acc book = acc + priceAsDouble $ bookPrice book

<interactive>:10:57:
Couldn't match expected type ‘Double’
            with actual type ‘Price -> Double’
Probable cause: ‘priceAsDouble’ is applied to too few arguments
In the second argument of ‘(+)’, namely ‘priceAsDouble’
In the expression: acc + priceAsDouble
Run Code Online (Sandbox Code Playgroud)

问题:我认为($)只不过是圆括号()的语法糖.显然,我错了.我想到的错误在哪里?

JB.*_*JB. 6

$ 括号的语法糖,但它不适用于您期望的水平.

go acc book = acc + priceAsDouble $ bookPrice book
Run Code Online (Sandbox Code Playgroud)

实际上被解释为

go acc book = (acc + priceAsDouble) (bookPrice book)
Run Code Online (Sandbox Code Playgroud)

acc + priceAsDouble作为GHC的功能没有意义.

具有讽刺意味的是,你需要更多的括号来使它工作:

go acc book = acc + (priceAsDouble $ bookPrice book)
Run Code Online (Sandbox Code Playgroud)

  • @gspr它曾经只是一个简单的函数,但GHC现在把`$`用作中缀作为实际的语法糖.这使得它使用高级类型扩展可以更好地工作. (6认同)
  • 另请注意,`($)`是一种非常简单的语法糖:它只是一个完全普通的Haskell函数,定义为`($)fx = fx`,并使用最低的右关联预设('infixr 0`)作为中缀). (2认同)