Вопрос

В чем разница между точкой (.) и знак доллара ($)?

Насколько я понимаю, они оба являются синтаксическим сахаром, поскольку нет необходимости использовать круглые скобки.

Это было полезно?

Решение

Тот Самый $ оператор предназначен для того, чтобы избегать круглых скобок.Все, что появляется после этого, будет иметь приоритет над всем, что было до этого.

Например, предположим, у вас есть строка следующего содержания:

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

Вы можете связать цепью show Для putStrLn вот так:

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

Использование (.) часто их немного сложнее заменить;обычно им требуется лямбда-выражение или введение явного параметра функции.Например:

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'

Приведенный выше пример, возможно, является иллюстративным, но на самом деле не показывает удобства использования composition .Вот еще одна аналогия:

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

Если мы используем third только один раз, мы можем избежать присвоения ему имени с помощью лямбда:

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

Наконец, композиция позволяет нам избежать лямбда-выражения:

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

Короткая и приятная версия:

  • ($) вызывает функцию, которая является ее левым аргументом, для значения, которое является ее правым аргументом.
  • (.) создает функцию, которая является ее левым аргументом, из функции, которая является ее правым аргументом.

Одно приложение, которое является полезным, и мне потребовалось некоторое время, чтобы разобраться с очень коротким описанием в learn you a 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

это то же самое, что создание функции, которая передает результат своего аргумента, переданного 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

Заключение

Используйте композицию, когда вам не нужно немедленно оценивать функцию.Возможно, вы хотите передать функцию, которая является результатом композиции, другой функции.

Используйте приложение, когда вы предоставляете все аргументы для полной оценки.

Итак, для нашего примера было бы семантически предпочтительнее сделать

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 type checker допускает установку с более высокими ранговыми / количественными типами.Если вы посмотрите на тип $ id например, вы обнаружите, что он будет принимать функцию, аргумент которой сам по себе является полиморфной функцией.Подобные мелочи не обеспечивают такой гибкости при использовании эквивалентного оператора расстроенных данных.(Это на самом деле заставляет меня задуматься, если $!заслуживает такого же отношения или нет )

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top