I'm just learning Haskell and I'm still not entirely clear on when and how strict evaluation is forced
When I want a function to evaluate its arguments strictly I find myself writing
((f $! x) $! y ) $! z
which seems weird. Shouldn't $! be left-associative so I could write
f $! x $! y $! z
and have it do what I want?
Am I completely misunderstanding the $! operator?
The right-associativity of the = operator allows expressions such as a = b = c to be interpreted as a = (b = c) . In C++, the assignment a = b is an expression that evaluates to the same value as the expression a , with the side effect of storing the R-value of b into the L-value of a .
The operator = is right-associative, which means that a = b = c is equivalent to a = (b = c) , as opposed to (a = b) = c . Associativity has nothing to do with the order of evaluation. "Associativity has nothing to do with the order of evaluation." Well, unless all the operators have the same precedence.
Associativity can be either Left to Right or Right to Left. For example: '*' and '/' have same precedence and their associativity is Left to Right, so the expression “100 / 10 * 10” is treated as “(100 / 10) * 10”. 1) Associativity is only used when there are two or more operators of same precedence.
The ** operator follows normal mathematical conventions; it is right-associative: In the usual computer science jargon, exponentiation in mathematics is right-associative, which means that xyz should be read as x(yz), not (xy)z.
It's to mirror the fixity of $
. You could make a very good case for both $
and $!
having the wrong fixity.
I found a proposal from 2008 in haskell-prime to make the $
and $!
operators left-associative:
https://ghc.haskell.org/trac/haskell-prime/wiki/ChangeDollarAssociativity
There is only one argument against the proposal: "This would break a lot of code".
Instead, there are given four arguments in favour of left-associative ($)
, the last one being the same as yours, and considered the most important. They are, in short:
0) given the expression f x y
, with two applications, we would be able to write f $ x $ y
1) now, with right associative ($)
, we can write f . g . h $ x
as f $ g $ h $ x
,
however: \x -> f $ g $ h $ x ==> f $ g $ h
is invalid,
so that writing such pipelines with composition is better, as it allows easier cleanup of code
2) Left associative ($) allows you to eliminate more parentheses, in addition to the ones eliminated with (.), for instance:
f (g x) (h y) ==> f $ g x $ h y
3) your argument: the right associative version of $!
is inconvenient because of giving rise to things like: ((f $! x) $! y) $! z
instead of f $! x $! y $! z
I give support to use the better left-associative version of application operators redefining them at the beginning of our code, like this:
import Prelude hiding (($), ($!))
infixl 0 $, $!
($), ($!) :: (a -> b) -> a -> b
f $ x = f x
f $! x = x `seq` f x
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With