Hutton's "Programming in Haskell", first edition, says that the concatenation operator
could be defined as:
( ys) = foldr (:) ys
This makes logical sense.
I had never seen an operator being defined by an equation on one of its sections (in this case ( ys)
), so I tried it myself:
(@@) :: [a] -> [a] -> [a]
(@@ ys) = foldr (:) ys
However this doesn't compile, higlighting a syntax error in (@@ ys)
.
Has this never been a feature, or has it been removed at some point? If so, why?
I know I could write the above as:
xs @@ ys = foldr (:) ys xs
But I find the point-free style more elegant.
CodePudding user response:
This would result in some subtle inconsistencies. Although we tend to think of curried and flipped and uncurried functions as just different ways of writing the same thing, that is not quite true when it comes to the actual evaluation strategy. Consider
(#>) :: Integer -> Integer -> Integer
(#>) n = let p = {- the `n`-th prime number -} `mod` 74
in (p )
Indexing prime numbers is costly. If you write something like
map ((2^43) #>) [100 .. 150]
then the 243-th prime number needs to be computed only once. By contrast, if I define
(<#) :: Integer -> Integer -> Integer
(<#) = flip foo
then writing map (<# (2^43)) [100 .. 150]
would compute the prime number over and over again, because Haskell doesn't support partially applying functions on the second argument.
With the flip foo
definition this isn't too surprising, but if I could have defined the flipped form directly as
(<#n) = let p = {- the `n`-th prime number -} `mod` 74
in (p )
then one could reasonably expect that map (<# (2^43))
does share the prime computation, but to support that Haskell's partial evaluation semantics would need to track more information than they currently do, and if we want this to work reliably then it would probably incur some other disadvantages.