(Ab)use the Reader Monad/Applicative
There already are comments on pointfree code and one mentioning pure
, but I figured I'd make a specific tip for this since I see it a lot.
The Applicative functions in Prelude
by default when specialized to functions are as follows
instance Applicative ((->) a) where
pure = const
(f <*> g) x = f x (g x)
Note that for this particular type, (=<<)
acts almost the same as (<*>)
, except it takes its second argument flipped (thanks @ØrjanJohansen).
pure
is one character shorter than const
, as mentioned elsewhere. The especially useful combinator, however, is (<*>)
. Below are examples of where I've used it recently.
The straightforward way to solve this is
import Data.List
map(\x->(x!!0,length x)).group.sort
But we're here for codegolf, not readable code.
import Data.List
map((,).nub<*>length).group.sort
A contrived function
This comes from a function my coworker wrote that I (unashamedly) golfed until it was unreadable.
Suppose we have
data Ex a b c
= Ex
{ foo :: [(a,b)]
, bar :: c}
and we want the natural implementation of a function
f :: Ex a b c -> [(a,c)]
I don't have the original solution (it did involve (&&&)
from Control.Arrow
, though), but the golfed one using (<*>)
is
map.fmap.pure.bar<*>foo
which also abuses the Functor
instance of (,) a
.
digitSum(n) + n
This golf is part of this answer.
This is a pretty well-golfed function
\n->n+sum[read[d]|d<-show n]
but if we do away with readability and bring in (<*>)
, we can shave off a character:
foldr((+).read.pure)<*>show
-- = \x -> foldr ((+) . read . pure) x (show x)
do notation
If your function is of the form \x -> (expr) x
and (expr)
contains some repeated blah x
often, you can sometimes save bytes with Reader monad do
notation and b<-blah
.
Here are some strange examples:
\x->max(div x 3*div x 5^div x 7)x -- original expression
f x|d<-div x=max(d 3*d 5^d 7)x;f -- define f=... then use f
\x->max(x!3*x!5^x^7)x;(!)=div -- define (!)=div
do d<-div;max$d 3*d 5^d 7 -- aha!
\x->product x:filter(/=product x)x -- original expression
(:)<$>product<*>(filter=<<(/=).product) -- yeah, no...
f x|p<-product x=p:filter(/=p)x;f -- define f=... then use f
\x->p x:filter(/=p x)x;p=product -- define p=product
do p<-product;(p:).filter(/=p) -- aha!
In general, do a<-b;c<-d;e
is equivalent to \x->let{a=b x;c=d x}in e x
.