Haskell: разница между .
(точка) и $
(знак доллара)
В чем разница между точкой (.)
и знаком доллара ($)
?. Насколько я понимаю, они оба являются синтаксическим сахаром для того, чтобы не использовать скобки.
Они являются , а не синтаксическим сахаром, для которого нет необходимости использовать круглые скобки - они являются функциями, - вставлены, поэтому мы можем называть их операторами.
Составьте, (.)
, и когда его использовать.
(.)
- функция составления. Итак
result = (f . g) x
- это то же самое, что создание функции, которая передает результат своего аргумента, переданного в g
, в f
.
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
Заключение
Используйте композицию, когда вам не нужно сразу оценивать функцию. Возможно, вы хотите передать функцию, полученную в результате композиции, другой функции.
Используйте приложение, когда вы предоставляете все аргументы для полной оценки.
Так что для нашего примера было бы семантически предпочтительнее сделать
f $ g x
когда у нас есть x
(точнее, g
аргументы), и делаем:
f . g
когда мы этого не сделаем.