点(.)和美元符号($)的区别是什么?
根据我的理解,它们都是不需要使用括号的语法糖。
点(.)和美元符号($)的区别是什么?
根据我的理解,它们都是不需要使用括号的语法糖。
当前回答
哈斯克尔:区别。(点)和$(美元符号) 点(.)和美元符号($)的区别是什么?根据我的理解,它们都是不需要使用括号的语法糖。
它们不是不需要括号的语法糖——它们是固定的函数,因此我们可以称它们为操作符。
撰写,(.),以及何时使用它。
(.)为合成函数。所以
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
当我们不这样做的时候。
其他回答
简短而甜蜜的版本:
($)调用作为其左实参的函数对作为其右实参的值进行调用。 (.)将作为其左参数的函数组合到作为其右参数的函数上。
关于$最重要的部分是它具有最低的操作符优先级。
如果你输入info,你会看到:
λ> :info ($)
($) :: (a -> b) -> a -> b
-- Defined in ‘GHC.Base’
infixr 0 $
这告诉我们它是一个具有右结合性的中缀运算符,具有最低的可能优先级。普通函数应用程序是左关联的,具有最高优先级(10)。$正好相反。
所以我们在普通函数application或using()不起作用的地方使用它。
例如,这是可行的:
λ> head . sort $ "example"
λ> e
但这不是:
λ> head . sort "example"
因为。(sort "example")的优先级比sort低,类型是[Char]
λ> :type (sort "example")
(sort "example") :: [Char]
但是。需要两个函数,没有一个简单的方法来实现因为排序和操作的顺序。
哈斯克尔:区别。(点)和$(美元符号) 点(.)和美元符号($)的区别是什么?根据我的理解,它们都是不需要使用括号的语法糖。
它们不是不需要括号的语法糖——它们是固定的函数,因此我们可以称它们为操作符。
撰写,(.),以及何时使用它。
(.)为合成函数。所以
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
当我们不这样做的时候。
我的规则很简单(我也是初学者):
不要使用。如果要传递参数(调用函数),和 如果没有参数,不要使用$(合成一个函数)
这是
show $ head [1, 2]
但从来没有:
show . head [1, 2]
还要注意,($)是专门用于函数类型的标识函数。恒等函数是这样的:
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)