2

这发生在您想将一堆函数应用于同一个变量的情况下,它可能如下所示:

map (\f->f 4) [odd, even]

但是来自LYAH 的使用$使它非常整洁

map ($ 4) [odd, even]

为什么它起作用。首先我在 ghci like 中输入它$ 4 odd,它失败了,然后我输入($ 4) odd它,它工作正常。然后我检查显示的($ 4)使用类型,是。这似乎有道理,但对我来说仍然不清楚。:t($ 4) :: Num a => (a -> b) -> boddodd :: Integral a => a -> Bool

谁能解释清楚,它是另一种常见的用法吗?$还有其他更多用法吗$

4

3 回答 3

7

操作员解剖

$应用程序运算符的形式为:

($) :: (a -> b) -> a -> b

当您想避免使用尾随括号时,通常会出现这种情况:

func a (b + c)

等于:

func a $ b + c

这背后的魔力在其固定性声明中得到了简单的解释:

infixr 0

这意味着:后面的所有内容都$将被分组到一个实体中,就像它们被括在括号中一样。

当然这也可以像这样“嵌套”:

func a $ b + other $ c - d

意思是:

func a (b + other (c - d))

应用运算符作为函数

您的案例非常有趣,根据我的经验,不经常使用。

我们来分析一下:

map ($ 4) [odd, even]

我们知道map的类型是:

map :: (a -> b) -> [a] -> [b]

如果有人忘记了,行为是:获取第一个参数(从ato的函数b)并将其应用于a第二个参数列表中的每个,最后返回结果列表。

您可以将($ 4)其视为“将 4 作为参数传递给某物”。意思就是:

($ 4) func

是相同的:

func $ 4

所以:

map ($ 4) [odd, even]

方法:

[($ 4) odd, ($ 4) even]
[(odd $ 4), (even $ 4)]
[False, True]

为什么 (func $) 不是必需的

您可以争辩说,就像您可以做的那样(/ 4)(2 /)分别表示“将某物除以 4”和“将 2 除以某物”,您可以这样做($ 4)(func $)而且您是对的。

实际上:

(func $) 4

是相同的:

func $ 4
func 4

这与以下内容相同:

($ 4) func

但现实是:

map (func $) [...]

将是不必要的,因为第一个参数map总是应用于列表的每个参数,使上述相同:

map func [...]
于 2014-08-25T15:14:00.757 回答
3
  1. $ 4 odd: 这不起作用,因为运算符在不以中缀形式使用时必须用括号括起来。如果你这样做($) 4 odd,这将不起作用,因为参数顺序不正确,你想4成为第二个参数。不过你可以写($) odd 4

  2. ($ 4) odd:这确实有效,因为它使用了操作符sections,这里4提供了作为第二个参数$。就像(++ "world") "hello "是一样"hello " ++ "world"

  3. 当你有($ 4) :: Num a => (a -> b) -> b, 和odd :: Integral a => a -> Bool时,你只需要排列类型。由于 everyIntegral a也是 a Num a,我们可以“升级”(约束)NumtoIntegral使其工作:

($ 4) :: Integral a => (a ->    b) -> b
odd   :: Integral a =>  a -> Bool

所以a ~ ab ~ Bool,所以你可以这么说

($ 4) :: Integral a => (a -> Bool) -> Bool

所以应用它odd给我们

($ 4) odd :: Bool

这是因为($ 4) odd与 相同odd $ 4。查看 的定义$

f $ x = f x

我们可以这么说

odd $ 4 = odd 4

评估为False

于 2014-08-25T15:17:17.847 回答
3

中缀运算符,如*,++$通常采用两个参数,如

x ++ y

当缺少一个参数并将它们放在括号之间时,它们会形成一个部分

(x ++)
(++ y)

这些部分分别相当于,

\y -> x ++ y
\x -> x ++ y

即,它们代表将“缺少的参数”映射到结果的函数。例如,

map ("A"++) ["a","b"] == [ "Aa","Ab" ]
map (++"A") ["a","b"] == [ "aA","bA" ]

运营商$在这方面并不特殊。我们有

(f $)
($ x)

代表

\x -> f $ x
\f -> f $ x

第一个不是很有用,因为(f $)\x -> f $ x是 (eta-) 等价于f(*)。第二个反而有用。

(*) 要挑剔,seq可以区分undefined(undefined $),但这在实践中是细微的差别。

于 2014-08-25T15:17:24.037 回答