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

时间:2021-01-24 22:32:23

What is the difference between the dot (.) and the dollar sign ($)?. As I understand it, they are both syntactic sugar for not needing to use parentheses.

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

12 个解决方案

#1


The $ operator is for avoiding parentheses. Anything appearing after it will take precedence over anything that comes before.

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

For example, let's say you've got a line that reads:

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

putStrLn (show (1 + 1))

If you want to get rid of those parentheses, any of the following lines would also do the same thing:

如果你想摆脱这些括号,以下任何一行也会做同样的事情:

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

The primary purpose of the . operator is not to avoid parentheses, but to chain functions. It lets you tie the output of whatever appears on the right to the input of whatever appears on the left. This usually also results in fewer parentheses, but works differently.

的主要目的。运算符不是为了避免括号,而是为了链函数。它允许您将右侧显示的内容输出与左​​侧显示的输入相关联。这通常也会导致括号减少,但工作方式不同。

Going back to the same example:

回到相同的例子:

putStrLn (show (1 + 1))
  1. (1 + 1) doesn't have an input, and therefore cannot be used with the . operator.
  2. (1 + 1)没有输入,因此不能与之一起使用。运营商。

  3. show can take an Int and return a String.
  4. show可以获取Int并返回一个String。

  5. putStrLn can take a String and return an IO ().
  6. putStrLn可以获取一个String并返回一个IO()。

You can chain show to putStrLn like this:

你可以像这样链显示putStrLn:

(putStrLn . show) (1 + 1)

If that's too many parentheses for your liking, get rid of them with the $ operator:

如果您喜欢这个括号太多,请使用$运算符删除它们:

putStrLn . show $ 1 + 1

#2


They have different types and different definitions:

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

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

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

($) is intended to replace normal function application but at a different precedence to help avoid parentheses. (.) is for composing two functions together to make a new function.

($)旨在取代正常的函数应用程序,但以不同的优先级来帮助避免使用括号。 (。)用于组合两个函数以创建新函数。

In some cases they are interchangeable, but this is not true in general. The typical example where they are is:

在某些情况下,它们是可以互换的,但总的来说并非如此。它们的典型示例是:

f $ g $ h $ x

==>

f . g . h $ x

In other words in a chain of $s, all but the final one can be replaced by .

换句话说,在$ s链中,除最后一个之外的所有链接都可以替换为。

#3


Also note that ($) is the identity function specialised to function types. The identity function looks like this:

另请注意,($)是专用于函数类型的标识函数。标识函数如下所示:

id :: a -> a
id x = x

While ($) looks like this:

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

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

Note that I've intentionally added extra parentheses in the type signature.

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

Uses of ($) can usually be eliminated by adding parenthesis (unless the operator is used in a section). E.g.: f $ g x becomes f (g x).

通常可以通过添加括号来消除($)的使用(除非在一节中使用运算符)。例如:f $ g x变为f(g x)。

Uses of (.) are often slightly harder to replace; they usually need a lambda or the introduction of an explicit function parameter. For example:

(。)的使用通常稍微难以替换;它们通常需要lambda或引入显式函数参数。例如:

f = g . h

becomes

f x = (g . h) x

becomes

f x = g (h x)

Hope this helps!

希望这可以帮助!

#4


($) allows functions to be chained together without adding parentheses to control evaluation order:

($)允许将函数链接在一起而不添加括号来控制评估顺序:

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

Prelude> head $ tail "asdf"
's'

The compose operator (.) creates a new function without specifying the arguments:

compose运算符(。)创建一个新函数而不指定参数:

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

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

The example above is arguably illustrative, but doesn't really show the convenience of using composition. Here's another analogy:

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

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

If we only use third once, we can avoid naming it by using a lambda:

如果我们只使用第三次,我们可以避免使用lambda来命名它:

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

Finally, composition lets us avoid the lambda:

最后,组合让我们避免lambda:

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

#5


The short and sweet version:

简短而甜蜜的版本:

  • ($) calls the function which is its left-hand argument on the value which is its right-hand argument.
  • ($)调用函数,该函数是其右手参数值的左手参数。

  • (.) composes the function which is its left-hand argument on the function which is its right-hand argument.
  • (。)组成函数,它是函数的左手参数,它是右手参数。

#6


One application that is useful and took me some time to figure out from the very short description at learn you a haskell: Since:

一个有用的应用程序,花了我一些时间从非常简短的描述中弄清楚了解一个haskell:自:

f $ x = f x

and parenthesizing the right hand side of an expression containing an infix operator converts it to a prefix function, one can write ($ 3) (4+) analogous to (++", world") "hello".

并且将包含中缀运算符的表达式的右侧括起来将其转换为前缀函数,可以写入($ 3)(4+)类似于(++“,world”)“hello”。

Why would anyone do this? For lists of functions, for example. Both:

为什么有人会这样做?例如,对于函数列表。都:

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

and:

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

are shorter than map (\x -> x ++ ", world") ... or map (\f -> f 3) .... Obviously, the latter variants would be more readable for most people.

比map(\ x - > x ++“,world”)...或map(\ f - > f 3)短......显然,后面的变体对大多数人来说更具可读性。

#7


... or you could avoid the . and $ constructions by using pipelining:

......或者你可以避免。和使用流水线的$构造:

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

That's after you've added in the helper function:

在您添加辅助函数之后:

(|>) x y = y x

#8


A great way to learn more about anything (any function) is to remember that everything is a function! That general mantra helps, but in specific cases like operators, it helps to remember this little trick:

了解任何事物(任何功能)的好方法是记住一切都是功能!一般的口头禅有所帮助,但在特定情况下,如操作员,它有助于记住这个小技巧:

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

and

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

Just remember to use :t liberally, and wrap your operators in ()!

只记得使用:t*,并将你的运算符包装在()中!

#9


My rule is simple (I'm beginner too):

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

  • do not use . if you want to pass the parameter (call the function), and
  • 不使用 。如果你想传递参数(调用函数),和

  • do not use $ if there is no parameter yet (compose a function)
  • 如果还没有参数,请不要使用$(撰写函数)

That is

show $ head [1, 2]

but never:

show . head [1, 2]

#10


Haskell: difference between . (dot) and $ (dollar sign)

What is the difference between the dot (.) and the dollar sign ($)?. As I understand it, they are both syntactic sugar for not needing to use parentheses.

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

They are not syntactic sugar for not needing to use parentheses - they are functions, - infixed, thus we may call them operators.

它们不是语法糖,因为不需要使用括号 - 它们是函数, - 无效,因此我们可以将它们称为运算符。

(.) is the compose function. So

(。)是撰写函数。所以

result = (f . g) x

is the same as building a function that passes the result of its argument passed to g on to f.

与构建一个函数相同,该函数将传递给g的参数的结果传递给f。

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

($) is a right-associative apply function with low binding precedence. So it merely calculates the things to the right of it first. Thus,

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

result = f $ g x

is the same as this, procedurally (which matters since Haskell is evaluated lazily, it will begin to evaluate f first):

在程序上是这样的(这很重要,因为Haskell被懒惰地评估,它将首先开始评估f):

h = f
g_x = g x
result = h g_x

or more concisely:

或者更简洁:

result = f (g x)

We can see this by reading the source for each function.

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

Read the Source

Here's the source for (.):

这是(。)的来源:

-- | 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)

And here's the source for ($):

这是($)的来源:

-- | 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

When to use:

Use composition when you do not need to immediately evaluate the function. Maybe you want to pass the function that results from composition to another function.

当您不需要立即评估函数时使用合成。也许你想将由合成产生的函数传递给另一个函数。

Use application when you are supplying all arguments for full evaluation.

在提供完整评估的所有参数时使用应用程序。

So for our example, it would be semantically preferable to do

因此,对于我们的示例,它在语义上是可取的

f $ g x

when we have x (or rather, g's arguments), and do:

当我们有x(或更确切地说,g的参数),并且:

f . g

when we don't.

当我们没有。

#11


I think a short example of where you would use . and not $ would help clarify things.

我想一个你要用的地方的简短例子。而不是$将有助于澄清事情。

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

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

Note that times6 is a function that is created from function composition.

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

#12


All the other answers are pretty good. But there’s an important usability detail about how ghc treats $, that the ghc type checker allows for instatiarion with higher rank/ quantified types. If you look at the type of $ id for example you’ll find it’s gonna take a function whose argument is itself a polymorphic function. Little things like that aren’t given the same flexibility with an equivalent upset operator. (This actually makes me wonder if $! deserves the same treatment or not )

所有其他答案都很好。但是关于ghc如何处理$,有一个重要的可用性细节,ghc类型检查器允许更高级别/量化类型的instatiarion。如果你看一下$ id的类型,你会发现它将采用一个函数,其参数本身就是一个多态函数。像这样的小事情与同等的沮丧操作员没有相同的灵活性。 (这实际上让我想知道$!是否值得同样的待遇)

#1


The $ operator is for avoiding parentheses. Anything appearing after it will take precedence over anything that comes before.

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

For example, let's say you've got a line that reads:

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

putStrLn (show (1 + 1))

If you want to get rid of those parentheses, any of the following lines would also do the same thing:

如果你想摆脱这些括号,以下任何一行也会做同样的事情:

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

The primary purpose of the . operator is not to avoid parentheses, but to chain functions. It lets you tie the output of whatever appears on the right to the input of whatever appears on the left. This usually also results in fewer parentheses, but works differently.

的主要目的。运算符不是为了避免括号,而是为了链函数。它允许您将右侧显示的内容输出与左​​侧显示的输入相关联。这通常也会导致括号减少,但工作方式不同。

Going back to the same example:

回到相同的例子:

putStrLn (show (1 + 1))
  1. (1 + 1) doesn't have an input, and therefore cannot be used with the . operator.
  2. (1 + 1)没有输入,因此不能与之一起使用。运营商。

  3. show can take an Int and return a String.
  4. show可以获取Int并返回一个String。

  5. putStrLn can take a String and return an IO ().
  6. putStrLn可以获取一个String并返回一个IO()。

You can chain show to putStrLn like this:

你可以像这样链显示putStrLn:

(putStrLn . show) (1 + 1)

If that's too many parentheses for your liking, get rid of them with the $ operator:

如果您喜欢这个括号太多,请使用$运算符删除它们:

putStrLn . show $ 1 + 1

#2


They have different types and different definitions:

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

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

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

($) is intended to replace normal function application but at a different precedence to help avoid parentheses. (.) is for composing two functions together to make a new function.

($)旨在取代正常的函数应用程序,但以不同的优先级来帮助避免使用括号。 (。)用于组合两个函数以创建新函数。

In some cases they are interchangeable, but this is not true in general. The typical example where they are is:

在某些情况下,它们是可以互换的,但总的来说并非如此。它们的典型示例是:

f $ g $ h $ x

==>

f . g . h $ x

In other words in a chain of $s, all but the final one can be replaced by .

换句话说,在$ s链中,除最后一个之外的所有链接都可以替换为。

#3


Also note that ($) is the identity function specialised to function types. The identity function looks like this:

另请注意,($)是专用于函数类型的标识函数。标识函数如下所示:

id :: a -> a
id x = x

While ($) looks like this:

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

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

Note that I've intentionally added extra parentheses in the type signature.

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

Uses of ($) can usually be eliminated by adding parenthesis (unless the operator is used in a section). E.g.: f $ g x becomes f (g x).

通常可以通过添加括号来消除($)的使用(除非在一节中使用运算符)。例如:f $ g x变为f(g x)。

Uses of (.) are often slightly harder to replace; they usually need a lambda or the introduction of an explicit function parameter. For example:

(。)的使用通常稍微难以替换;它们通常需要lambda或引入显式函数参数。例如:

f = g . h

becomes

f x = (g . h) x

becomes

f x = g (h x)

Hope this helps!

希望这可以帮助!

#4


($) allows functions to be chained together without adding parentheses to control evaluation order:

($)允许将函数链接在一起而不添加括号来控制评估顺序:

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

Prelude> head $ tail "asdf"
's'

The compose operator (.) creates a new function without specifying the arguments:

compose运算符(。)创建一个新函数而不指定参数:

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

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

The example above is arguably illustrative, but doesn't really show the convenience of using composition. Here's another analogy:

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

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

If we only use third once, we can avoid naming it by using a lambda:

如果我们只使用第三次,我们可以避免使用lambda来命名它:

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

Finally, composition lets us avoid the lambda:

最后,组合让我们避免lambda:

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

#5


The short and sweet version:

简短而甜蜜的版本:

  • ($) calls the function which is its left-hand argument on the value which is its right-hand argument.
  • ($)调用函数,该函数是其右手参数值的左手参数。

  • (.) composes the function which is its left-hand argument on the function which is its right-hand argument.
  • (。)组成函数,它是函数的左手参数,它是右手参数。

#6


One application that is useful and took me some time to figure out from the very short description at learn you a haskell: Since:

一个有用的应用程序,花了我一些时间从非常简短的描述中弄清楚了解一个haskell:自:

f $ x = f x

and parenthesizing the right hand side of an expression containing an infix operator converts it to a prefix function, one can write ($ 3) (4+) analogous to (++", world") "hello".

并且将包含中缀运算符的表达式的右侧括起来将其转换为前缀函数,可以写入($ 3)(4+)类似于(++“,world”)“hello”。

Why would anyone do this? For lists of functions, for example. Both:

为什么有人会这样做?例如,对于函数列表。都:

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

and:

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

are shorter than map (\x -> x ++ ", world") ... or map (\f -> f 3) .... Obviously, the latter variants would be more readable for most people.

比map(\ x - > x ++“,world”)...或map(\ f - > f 3)短......显然,后面的变体对大多数人来说更具可读性。

#7


... or you could avoid the . and $ constructions by using pipelining:

......或者你可以避免。和使用流水线的$构造:

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

That's after you've added in the helper function:

在您添加辅助函数之后:

(|>) x y = y x

#8


A great way to learn more about anything (any function) is to remember that everything is a function! That general mantra helps, but in specific cases like operators, it helps to remember this little trick:

了解任何事物(任何功能)的好方法是记住一切都是功能!一般的口头禅有所帮助,但在特定情况下,如操作员,它有助于记住这个小技巧:

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

and

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

Just remember to use :t liberally, and wrap your operators in ()!

只记得使用:t*,并将你的运算符包装在()中!

#9


My rule is simple (I'm beginner too):

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

  • do not use . if you want to pass the parameter (call the function), and
  • 不使用 。如果你想传递参数(调用函数),和

  • do not use $ if there is no parameter yet (compose a function)
  • 如果还没有参数,请不要使用$(撰写函数)

That is

show $ head [1, 2]

but never:

show . head [1, 2]

#10


Haskell: difference between . (dot) and $ (dollar sign)

What is the difference between the dot (.) and the dollar sign ($)?. As I understand it, they are both syntactic sugar for not needing to use parentheses.

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

They are not syntactic sugar for not needing to use parentheses - they are functions, - infixed, thus we may call them operators.

它们不是语法糖,因为不需要使用括号 - 它们是函数, - 无效,因此我们可以将它们称为运算符。

(.) is the compose function. So

(。)是撰写函数。所以

result = (f . g) x

is the same as building a function that passes the result of its argument passed to g on to f.

与构建一个函数相同,该函数将传递给g的参数的结果传递给f。

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

($) is a right-associative apply function with low binding precedence. So it merely calculates the things to the right of it first. Thus,

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

result = f $ g x

is the same as this, procedurally (which matters since Haskell is evaluated lazily, it will begin to evaluate f first):

在程序上是这样的(这很重要,因为Haskell被懒惰地评估,它将首先开始评估f):

h = f
g_x = g x
result = h g_x

or more concisely:

或者更简洁:

result = f (g x)

We can see this by reading the source for each function.

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

Read the Source

Here's the source for (.):

这是(。)的来源:

-- | 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)

And here's the source for ($):

这是($)的来源:

-- | 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

When to use:

Use composition when you do not need to immediately evaluate the function. Maybe you want to pass the function that results from composition to another function.

当您不需要立即评估函数时使用合成。也许你想将由合成产生的函数传递给另一个函数。

Use application when you are supplying all arguments for full evaluation.

在提供完整评估的所有参数时使用应用程序。

So for our example, it would be semantically preferable to do

因此,对于我们的示例,它在语义上是可取的

f $ g x

when we have x (or rather, g's arguments), and do:

当我们有x(或更确切地说,g的参数),并且:

f . g

when we don't.

当我们没有。

#11


I think a short example of where you would use . and not $ would help clarify things.

我想一个你要用的地方的简短例子。而不是$将有助于澄清事情。

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

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

Note that times6 is a function that is created from function composition.

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

#12


All the other answers are pretty good. But there’s an important usability detail about how ghc treats $, that the ghc type checker allows for instatiarion with higher rank/ quantified types. If you look at the type of $ id for example you’ll find it’s gonna take a function whose argument is itself a polymorphic function. Little things like that aren’t given the same flexibility with an equivalent upset operator. (This actually makes me wonder if $! deserves the same treatment or not )

所有其他答案都很好。但是关于ghc如何处理$,有一个重要的可用性细节,ghc类型检查器允许更高级别/量化类型的instatiarion。如果你看一下$ id的类型,你会发现它将采用一个函数,其参数本身就是一个多态函数。像这样的小事情与同等的沮丧操作员没有相同的灵活性。 (这实际上让我想知道$!是否值得同样的待遇)