Monday, March 7, 2011

When should I use $ (and can it always be replaced with parentheses)?

From what I'm reading, $ is described as "applies a function to its arguments." However, it doesn't seem to work quite like (apply ...) in Lisp, because it's a binary operator, so really the only thing it looks like it does is help to avoid parentheses sometimes, like foo $ bar quux instead of foo (bar quux). Am I understanding it right? Is the latter form considered "bad style"?

From stackoverflow
  • You're mostly understanding it right---that is, about 99% of the use of $ is to help avoid parentheses, and yes, it does appear to be preferred to parentheses in most cases.

    Note, though:

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

    That is, $ is a function; as such, it can be passed to functions, composed with, and anything else you want to do with it. I think I've seen it used by people screwing with combinators before.

  • $ is preferred to parentheses when the distance between the opening and closing parens would otherwise be greater than good readability warrants, or if you have several layers of nested parentheses.

    For example

    i (h (g (f x)))
    

    can be rewritten

    i $ h $ g $ f x
    

    In other words, it represents right-associative function application. This is useful because ordinary function application associates to the left, i.e. the following

    i h g f x
    

    ...can be rewritten as follows

    (((i h) g) f) x
    

    Other handy uses of the ($) function include zipping a list with it:

    zipWith ($) fs xs
    

    This applies each function in a list of functions fs to a corresponding argument in the list xs, and collects the results in a list. Contrast with sequence fs x which applies a list of functions fs to a single argument x and collects the results; and fs <*> xs which applies each function in the list fs to every element of the list xs.

    Paul Johnson : A useful point about the daisy chain of $ signs is that it can be read a bit like a Unix pipeline, only going from right to left.
    Apocalisp : It can be read "a bit" like that, which is why it's best not to think of it that way.
  • The documentation of ($) answers your question. Unfortunately it isn't listed in the automatically generated documentation of the Prelude.

    However it is listed in the sourcecode which you can find here:

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

    However this module doesn't define ($) directly. The following, which is imported by the former, does:

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

    I included the relevant code below:

    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
    
  • Lots of good answers above, but one omission:

    $ cannot always be replace by parentheses

    But any application of $ can be eliminated by using parentheses, and any use of ($) can be replaced by id, since $ is a specialization of the identity function. Uses of (f$) can be replaced by f, but a use like ($x) (take a function as argument and apply it to x) don't have any obvious replacement that I see.

    Martijn : ($ x) is easily replaced by (\f -> f x)
  • If I look at your question and the answers here, Apocalisp and you are both right:

    • $ is preferred to parentheses under certain circumstances (see his answer)
    • foo (bar quux) is certainly not bad style!

    Also, please check out difference between . (dot) and $ (dollar sign), another SO question very much related to yours.

0 comments:

Post a Comment