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

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


当前回答

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

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链中,除了最后一个,其他的都可以被。

其他回答

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

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

While($)是这样的:

($) :: (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)

其他答案都很好。但是关于ghc如何处理$有一个重要的可用性细节,ghc类型检查器允许用更高等级/量化的类型进行初始化。例如,如果你看$ id类型你会发现它将接受一个参数本身是多态函数的函数。类似这样的小事情在等效的打乱操作符中没有相同的灵活性。(这实际上让我怀疑$!是否值得同样的待遇)

一个很有用的应用程序,我花了一些时间从Learn You a Haskell非常简短的描述中弄清楚:Since

f $ x = f x

在包含中缀运算符的表达式的右边加圆括号将其转换为前缀函数,可以将($ 3)(4 +)写成类似于(++ ",world")“你好”。

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

map (++ ", world") ["hello", "goodbye"]
map ($ 3) [(4 +), (3 *)]

map (\x -> x ++ ", world") ["hello", "goodbye"]
map (\f -> f 3) [(4 +), (3 *)]

显然,后一种变体对大多数人来说更具可读性。

哈斯克尔:区别。(点)和$(美元符号) 点(.)和美元符号($)的区别是什么?根据我的理解,它们都是不需要使用括号的语法糖。

它们不是不需要括号的语法糖——它们是固定的函数,因此我们可以称它们为操作符。

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

(.)为合成函数。所以

result = (f . g) x

这和构造一个函数是一样的,它把参数的结果传递给g,再传递给f。

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

当没有参数可以传递给想要组合的函数时,请使用(.)。

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

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

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

当我们不这样做的时候。