我有这样的印象,只要没有任何东西,我就可以$ ...用来表示.(...)...
但是,当我尝试重写以下内容时
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.