Use GHC 8.4.1 (or later)
With the Semigroup Monoid Proposal and the release of GHC 8.4.1, Semigroup
has been moved to the Prelude
. This gives us:
(<>) :: Semigroup a => a -> a -> a
Now these might seem useless at first glance, but looking closer we notice that Monoid a => (x -> a)
is an instance of Monoid
1, in which case we have the implementation:
(f <> g) xs = f xs <> g xs
This can be quite useful with for example lists, knowing that (<>)
is the same as (++)
for lists. So we have for example:
(init <> reverse) [1,2,3] ≡ init [1,2,3] <> reverse [1,2,3]
≡ [1,2] <> [3,2,1]
≡ [1,2] ++ [3,2,1]
≡ [1,2,3,2,1]
However, this is not the only useful case: Knowing that [x] -> [x]
is an instance of Monoid
, we also have a -> [x] -> [x]
an instance of Monoid
(you can iterate this as many times as you want):
(drop <> take) 2 [1,2,3,4,5] ≡ (drop 2 <> take 2) [1,2,3,4,5]
≡ drop 2 [1,2,3,4,5] <> take 2 [1,2,3,4,5]
≡ [3,4,5] <> [1,2]
≡ [3,4,5,1,2]
1: Note that Monoid a
\$\implies\$ Semigroup a
.
Overview what we gained so far
Using this trick we have these (not exhaustive) helpers, note that we can chain them:
duplicate = id <> id
triple² = id <> id <> id
palindromize = init <> reverse
rotateLeft = drop <> take
removeElementAt = take <> drop . succ
removeNElementsAt n = take <> drop . (+n)
2: This could also be ([1..3]>>)
for the same bytecount be shorter (see comment by Ørjan Johansen).
Where are the \$(\mathbb{Z},\texttt{+})\$ and \$(\mathbb{Z},\texttt{*})\$ monoids?
If we want to use the \$(\mathbb{Z},\texttt{+})\$ monoid, we need to tell GHC that. It can not decide for us which one it should use, therefore there are two newtype
s which allow this - Sum
and Product
.
Given that the consensus is to allow implicitly typed functions, we are probably allowed to do so if the challenge does not talk about a specific implementation for integers. Using this we can for example write \$n\$th oblong number as
id<>(+1)
which is shorter than f n=n*(n-1)
or even (*)=<<succ
/(*)<*>succ
.
Try it online!3
3: Note that we need to use (+1)
and cannot use succ
since GHC can't know that there is an instance of Enum
.
Other noteworthy related tricks
Instances that might be useful not covered above:
()
Ordering
(Monoid a, Monoid b) => Monoid (a,b) -- (also 3-,4- and 5-tuples)
Monoid a => Monoid (IO a)
Ord k => Monoid (Map k v) -- from Data.Map
It might be worth noting that there is mconcat
too:
mconcat [f1,f2,…,fN] ≡ f1 <> f2 <> … <> fN
This will probably not be useful often, for it needs at least \$3-11\$ functions (depending on the need of parentheses, see comments), but it might be in case you have some list Monoid a => [a]
already.
Furthermore mempty
can be useful since it is shorter than Nothing
or even pure Nothing
, ([],[])
etc.
Another useful instance is Monoid a => Monoid (IO a)
which has successfully been used for the currently shortest quine as
(putStr <> print) "foo" ≡ putStr "foo" <> print "foo"
≡ do x <- putStr "foo"
y <- print "foo"
pure $ x <> y
≡ do putStr "foo"
print "foo"
pure ()
≡ putStr "foo" >> print "foo"