点和点有什么区别 (.) 和美元符号 ($)?

据我了解,它们都是不需要使用括号的语法糖。

有帮助吗?

解决方案

$ 运算符是为了避免括号。在它之后出现的任何内容都将优先于之前出现的任何内容。

例如,假设您有一行内容如下:

putStrLn (show (1 + 1))

如果你想去掉这些括号,下面的任何一行也可以做同样的事情:

putStrLn (show $ 1 + 1)
putStrLn $ show (1 + 1)
putStrLn $ show $ 1 + 1

该项目的主要目的是 . 运算符并不是为了避免括号,而是为了链接函数。它可以让您将右侧出现的任何内容的输出与左侧出现的任何内容的输入联系起来。这通常也会导致括号更少,但工作方式不同。

回到同一个例子:

putStrLn (show (1 + 1))
  1. (1 + 1) 没有输入,因此不能与 . 操作员。
  2. show 可以采取 Int 并返回一个 String.
  3. putStrLn 可以采取 String 并返回一个 IO ().

你可以连锁 showputStrLn 像这样:

(putStrLn . show) (1 + 1)

如果您不喜欢括号太多,请使用 $ 操作员:

putStrLn . show $ 1 + 1

其他提示

它们具有不同类型和不同的定义:

infixr 9 .
(.) :: (b -> c) -> (a -> b) -> (a -> c)
(f . g) x = f (g x)

infixr 0 $
($) :: (a -> b) -> a -> b
f $ x = f x

($)旨在替代正常的功能的应用,但在不同的优先级,以帮助避免括号。 (.)是用于构成两个功能在一起,使一个新的功能。

在一些情况下,它们是可互换的,但是这是不正确的一般。其中它们的典型的例子是:

f $ g $ h $ x

==>

f . g . h $ x

在在$s链换句话说,所有但最后一个可以通过.代替

另外请注意,($)身份功能专门的功能类型。恒等函数看起来像这样:

id :: a -> a
id x = x

虽然($)看起来像这样:

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

请注意,我已经在类型签名有意添加额外的括号。

($)的使用,通常可以通过添加括号(除非操作者在一个部分中使用)来消除。例如: - f $ g x变得f (g x)

(.)的使用往往稍硬取代;他们通常需要一个lambda或引进一个明确的功能参数。例如:

f = g . h

变为

f x = (g . h) x

变为

f x = g (h x)

希望这有助于!

($)允许函数不添加括号控制计算顺序链接在一起:

Prelude> head (tail "asdf")
's'

Prelude> head $ tail "asdf"
's'

撰写操作者(.)创建一个新的功能,而无需指定参数:

Prelude> let second x = head $ tail x
Prelude> second "asdf"
's'

Prelude> let second = head . tail
Prelude> second "asdf"
's'

上面的例子可以说是说明性的,但并没有真正显示了使用组合物的便利性。下面是另一个类似于:

Prelude> let third x = head $ tail $ tail x
Prelude> map third ["asdf", "qwer", "1234"]
"de3"

如果我们只使用第三一次,我们能够避免使用一个lambda命名它:

Prelude> map (\x -> head $ tail $ tail x) ["asdf", "qwer", "1234"]
"de3"

最后,组合物让我们避免拉姆达:

Prelude> map (head . tail . tail) ["asdf", "qwer", "1234"]
"de3"

简短而甜蜜的版本:

  • ($) 在其右侧参数的值上调用其左侧参数的函数。
  • (.) 将其左侧参数的函数与其右侧参数的函数组合起来。

一个应用程序,它是有用的,我花了一些时间,从很短的描述找出在学习你Haskell的:日期:

f $ x = f x

和圆括号含有中缀运算符的表达式的右手侧将其转换为一个前缀的功能,一个可以写入($ 3) (4+)类似于(++", world") "hello"

为什么会有人这样做?对于相机的功能表,例如。这两种:

map (++", world") ["hello","goodbye"]`

map ($ 3) [(4+),(3*)]

map (\x -> x ++ ", world") ...map (\f -> f 3) ...短。显然,后者的变体将是对大多数人来说更具有可读性。

...或者你可以通过使用避免.$结构的流水线的:

third xs = xs |> tail |> tail |> head

这是你的助手功能已经添加后:

(|>) x y = y x

要了解任何一个伟大的方式(任何功能)是要记住,一切都是功能!这一般的口头禅帮助,但在具体情况下,像运营商,它有助于记住这个小窍门:

:t (.)
(.) :: (b -> c) -> (a -> b) -> a -> c

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

不过,别忘了自由的使用:t,和你的包裹运营商在()

我的规则很简单(我也是初学者):

  • 不使用 . 如果你想传递参数(调用函数),并且
  • 不使用 $ 如果还没有参数(组成一个函数)

那是

show $ head [1, 2]

但从来没有:

show . head [1, 2]

哈斯克尔:之间的区别 . (点)和 $ (美元符号)

点和点有什么区别 (.) 和美元符号 ($)?。据我了解,它们都是不需要使用括号的语法糖。

他们是 不是 不需要使用括号的语法糖 - 它们是函数, - 中固定,因此我们可以称它们为运算符。

撰写, (.), ,以及何时使用它。

(.) 是撰写功能。所以

result = (f . g) x

与构建一个将其参数的结果传递给的函数相同 gf.

h = \x -> f (g x)
result = h x

使用 (.) 当您没有可用于传递给您想要编写的函数的参数时。

右结合应用, ($), ,以及何时使用它

($) 是一个具有低绑定优先级的右关联应用函数。所以它只是先计算它右边的东西。因此,

result = f $ g x

与此相同,在程序上(这很重要,因为 Haskell 是惰性评估的,它将开始评估 f 第一的):

h = f
g_x = g x
result = h g_x

或者更简洁地说:

result = f (g x)

使用 ($) 在将前面的函数应用于结果之前,您需要评估所有变量。

我们可以通过阅读每个函数的源代码来看到这一点。

阅读源码

这是 来源 为了 (.):

-- | Function composition.
{-# INLINE (.) #-}
-- Make sure it has TWO args only on the left, so that it inlines
-- when applied to two functions, even if there is no final argument
(.)    :: (b -> c) -> (a -> b) -> a -> c
(.) f g = \x -> f (g x)

这是 来源 为了 ($):

-- | Application operator.  This operator is redundant, since ordinary
-- application @(f x)@ means the same as @(f '$' x)@. However, '$' has
-- low, right-associative binding precedence, so it sometimes allows
-- parentheses to be omitted; for example:
--
-- >     f $ g $ h x  =  f (g (h x))
--
-- It is also useful in higher-order situations, such as @'map' ('$' 0) xs@,
-- or @'Data.List.zipWith' ('$') fs xs@.
{-# INLINE ($) #-}
($)                     :: (a -> b) -> a -> b
f $ x                   =  f x

结论

当您不需要立即计算函数时,请使用组合。也许您想将组合产生的函数传递给另一个函数。

当您提供所有参数以进行全面评估时,请使用 application。

因此,对于我们的示例,语义上最好这样做

f $ g x

当我们有 x (更确切地说, g的论点),并执行以下操作:

f . g

当我们不这样做时。

我想,在那里你会使用.而不是$将有助于澄清事情很短的例子。

double x = x * 2
triple x = x * 3
times6 = double . triple

:i times6
times6 :: Num c => c -> c

请注意times6是从函数组合创建的函数。

所有其他的答案都还不错。但有关于如何对待GHC $一个重要的可用性的细节,该GHC类型检查允许以更高的等级/量化类型instatiarion。如果你看一下$ id例如类型,你会发现它会采取其参数本身就是一个多态函数的函数。这样的小事情没有给出具有同等心烦运营商同样的灵活性。 (这实际上使我怀疑$!值得同样的待遇或不)

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top