为何/何时不能在Haskell中使用$而不是括号?

tin*_*lyx 8 haskell

我有这样的印象,只要没有任何东西,我就可以$ ...用来表示.(...)...

但是,当我尝试重写以下内容时

dist' x y = abs  <$> ( (-) <$> x <*> y)
Run Code Online (Sandbox Code Playgroud)

dist x y = abs  <$> $ (-) <$> x <*> y
Run Code Online (Sandbox Code Playgroud)

我收到一个错误:

 error: …
    parse error on input ‘$’
    Perhaps you intended to use TemplateHaskell
  |
Compilation failed.
Run Code Online (Sandbox Code Playgroud)

我可以和写括号一起生活,但我只是好奇.为什么(或何时)$不能替换().

(这是GHC 8.2.2)

lef*_*out 11

虽然它实际上确实主要用于此目的,但是$操作符并不是在语法上与parenthisation相关联的任何基本方式 - 它只是另一个中缀运算符(即在参数之间写入的2参数函数),+或者*或者<$>.操作员所做的是在其左侧采用一个函数,在右侧采用该函数应该应用的值.所以,例如sqrt (1 - x^2)可以写sqrt $ 1 - x^2,因为sqrt仅仅是一个函数,而是平了应用功能,它的参数,你也可以用$做同样的事情,从低受益infixr 0 $.

该功能也可以是其他内容的组合或部分应用,如

(sum . map (^2)) (0 : xs)   ?   sum . map (^2) $ 0 : xs
Run Code Online (Sandbox Code Playgroud)

abs <$> ((-) <$> x <*> y)不是这种形式:它已经是一个中缀表达式.

然而,我们可以利用Haskell允许部分应用中缀运算符这一事实,因为它为您提供了一个简单的函数形式.你需要一个操作员部分:

abs <$> ((-) <$> x <*> y)   ?   (abs <$>) ((-) <$> x <*> y)
Run Code Online (Sandbox Code Playgroud)

现在这是一个简单的功能申请表,所以你可以做到

(abs <$>) $ (-) <$> x <*> y
Run Code Online (Sandbox Code Playgroud)

当然,这有点失败了,因为操作符部分引入了另一对括号,因此在这种情况下,编写表达式的原始方式可能仍然是最好的.幸运的是,<$>也有一种简单的功能形式,即

fmap abs $ (-) <$> x <*> y
Run Code Online (Sandbox Code Playgroud)

另一种选择是重写<*>子表达式:f <$> a <*> b与其相同liftA2 f a b,因为普通函数的绑定比中缀更紧密<$>.所以

abs <$> ((-) <$> x <*> y)   ?   abs <$> liftA2 (-) x y
Run Code Online (Sandbox Code Playgroud)

或者,fmap完全删除外部:如果您首先定义

numDist :: Num a => a -> a -> a
numDist a b = abs $ a - b
Run Code Online (Sandbox Code Playgroud)

然后你就可以写了

dist x y = numDist <$> x <*> y
Run Code Online (Sandbox Code Playgroud)

...要么

dist = liftA2 numDist
Run Code Online (Sandbox Code Playgroud)


Rah*_*nne 10

$是一个运营商,同样如<$>.问题是你有两个二元运算符相互跟随.

$由于其声明(infixr 0),它具有特定的方式,它具有最低优先级.(见:http://hackage.haskell.org/package/base-4.11.1.0/docs/Prelude.html#v : -36-)

有关更多信息,请参阅https://www.haskell.org/onlinereport/decls.html#fixity.