Esoteric uses for the ``$`` operator
====================================
The left-hand-side of the ``$`` operator
----------------------------------------
Mostly we've been concerned with what occurs on the right-hand-side of
the ``$`` operator. As we've now established, it also gathers up
everything on its left-hand-side (to the previous ``$`` operator or
the beginning of the expression), and this must yield a function.
Apart from simply naming a function (e.g. ``show`` in ``show $ x +
y``), the most common sort of expression that yields a function is a
partial application (e.g. ``map toLower``). Since function application
has higher precedence than any operator (effectively it has precedence
10, and associates to the left), partial application will always be
parsed as such. In other words, you never need to say ``map toLower $
s``: it means the same as ``map toLower s``.
Another sort of expression that yields a function is function
composition with the ``.`` operator. This has precedence 9 (and is
right associative), higher than any other operator, but lower than
function application. So the ``$`` operator can be used to group a
function composition correctly: rather than::
(reverse . takeWhile ('/' /=) . reverse) fp
you can write::
reverse . takeWhile ('/' /=) . reverse $ fp
The ``$`` operator in sections
------------------------------
As an operator, ``$`` is a candidate for making sections. A section is
a handy lump of syntactic sugar that effectively allows us to fix one
argument of an operator. A couple of example sections: ``('/' /=)`` is
the function that is ``False`` when its ``Char`` argument is ``'/'``
and ``True`` otherwise; ``(+ n)`` is the function that adds ``n`` to
its argument (obviously there must be a definition of ``n`` in scope).
In a right section, ``$`` is redundant. The section ``(f $)`` is
completely equivalent to ``(f)``, whether ``f`` is a simple expression
or a complex one. All the ``$`` could possibly do in this situation is
to group everything to its left, and the brackets on their own do that
just fine. (That's a handwavy sort of "proof": do let me know if you
can find a counter example!)
In a left section, ``$`` is more interesting. The section ``($ x)`` is
the function that takes a function argument and applies it to
``x``. For example, ``map ($ "foobar") [take 3, drop 3] ⇒
["foo","bar"]``. It's hard to think of a non-contrived use for this,
but I did manage it. I wanted to test the performance of various
different but - supposedly - equivalent definitions of a function. The
functions are named in the list ``timeFunctions``. Before the actual
timing tests, I thought it would be wise to check that the functions
indeed are equivalent (at least for the test arguments). The check for
equivalence for a single argument ``x`` is performed by this
function::
check x = all (r ==) rs
where
(r:rs) = map ($ x) timeFunctions
The entire timing harness is available as `timing.hs`_. It
demonstrates not only the ``$`` section, but also a use of ``seq``,
and the awesome power of lazy evaluation: the simplest definition is
(almost always) the fastest!
.. _timing.hs: http://static.tobold.org/dollar/timing.hs
The ``$`` operator as a function
--------------------------------
Finally, any operator can be turned into a function by enclosing it in
parentheses. Is there any use for the ``$`` operator as a function:
``($)``? The Haskell report offers ``zipWith ($) fs xs``: this takes a
list of functions and a list of arguments, and returns the list which
results from applying the first function to the first argument, the
second function to the second argument and so on. It's hard to see
that this has much to commend it over the equivalent list
comprehension, ``[ f x | (f, x) <- zip fs xs ]``. More seriously, I
can't think of a non-contrived use for such an expression!
A more likely scenario is that you'd like to apply each of a list
``fs`` of functions to *each* of a list ``xs`` of arguments. This
could be expressed by the list comprehension ``[ f x | f <- fs, x <-
xs ]``. It turns out that there is another way to express this, which
does use the ``($)`` function: the beautiful and mysterious ``liftM2
($) fs xs``. (Well, it's mysterious to me!) In fact, this expression
is simply the definition of ``ap`` (which, along with ``liftM2``, is
exported by ``Control.Monad``), so we can simply say ``ap fs xs``. All
three variants are included in `wc0.hs`_: a bare-bones implementation
of the Unix ``wc`` command, which counts the lines, words, and
characters in the files named on its command line.
.. _wc0.hs: http://static.tobold.org/dollar/wc0.hs
.. include:: wc0.hs
:literal:
Unfortunately, this version reports all the line counts, then all the
word counts, then all the character counts (in other words, the ``xs``
vary more quickly than the ``fs``). We'd prefer it to report all three
counts for the first file, then the second file, and so on (with the
``fs`` varying more quickly). This is trivial to fix with the list
comprehension: simply swap the order of the two generators. For the
``liftM2`` version, we can swap the ``fs`` and the ``xs``, and use the
function ``flip ($)``, but it's starting to look a bit murky. I can see
no simple remedy for the ``ap`` version, except to patch up the output
afterwards. Here's `wc1.hs`_ if you're feeling brave!
.. _wc1.hs: http://static.tobold.org/dollar/wc1.hs
In summary, there are a few cases where we can make us of the function
``($)``, but they are relatively rare. Do let me know if you come up
with a good use for ``($)``!