Когда я должен использовать $ (и всегда ли его можно заменить скобками)? - PullRequest
9 голосов
/ 28 декабря 2008

Из того, что я читаю, $ описывается как «применяет функцию к своим аргументам». Тем не менее, похоже, что он работает не совсем так, как (apply ...) в Лиспе, потому что это бинарный оператор, поэтому на самом деле единственное, что он делает, это помогает избежать скобок, например foo $ bar quux вместо foo (bar quux). Я правильно понимаю? Последняя форма считается "плохим стилем"?

Ответы [ 5 ]

18 голосов
/ 28 декабря 2008

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

Например

i (h (g (f x)))

можно переписать

i $ h $ g $ f x

Другими словами, оно представляет собой право-ассоциативное применение функции. Это полезно, потому что обычное приложение функции связывается слева, то есть следующее

i h g f x

... можно переписать следующим образом

(((i h) g) f) x

Другие удобные варианты использования функции ($) включают сжатие списка с ней:

zipWith ($) fs xs

Это применяет каждую функцию в списке функций fs к соответствующему аргументу в списке xs и собирает результаты в список. Сравните с sequence fs x, который применяет список функций fs к одному аргументу x и собирает результаты; и fs <*> xs, который применяет каждую функцию в списке fs к каждому элементу списка xs.

6 голосов
/ 28 декабря 2008

Вы в основном понимаете это правильно - то есть, около 99% использования $ - для того, чтобы избежать скобок, и да, в большинстве случаев он предпочитается скобкам.

Примечание, хотя:

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

То есть $ является функцией; как таковой, он может быть передан функциям, скомпонованным и всем остальным, что вы хотите с ним сделать. Я думаю, что раньше я видел, как люди этим занимались с комбинаторами.

4 голосов
/ 30 декабря 2008

Много хороших ответов выше, но одно упущение:

$ не всегда можно заменить скобками

Но любое применение $ может быть устранено с помощью скобок , а любое использование ($) может быть заменено на id, поскольку $ является специализацией тождественная функция . Использование (f$) может быть заменено на f, но использование, подобное ($x) (возьмите функцию в качестве аргумента и примените ее к x), не имеет очевидной замены, которую я вижу.

4 голосов
/ 28 декабря 2008

Документация ($) отвечает на ваш вопрос. К сожалению, он не указан в автоматически сгенерированной документации Prelude .

Однако он указан в исходном коде, который вы можете найти здесь:

http://darcs.haskell.org/packages/base/Prelude.hs

Однако этот модуль не определяет ($) напрямую. Следующее, которое импортируется первым, делает:

http://darcs.haskell.org/packages/base/GHC/Base.lhs

Я включил соответствующий код ниже:

infixr 0  $

...

-- | 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
1 голос
/ 26 июня 2009

Если я посмотрю на ваш вопрос и ответы здесь, Apocalisp и вы оба правы:

  • $ предпочтительнее скобок при определенных обстоятельствах (см. Его ответ)
  • foo (bar quux) конечно не плохой стиль!

Также, пожалуйста, проверьте разницу между. (точка) и $ (знак доллара) , еще один вопрос, очень связанный с вашим.

...