Degraded performance with constraint synonyms
The attached bug demonstrates how using constraint synonyms can negatively impact performance.
I have two functions which are identical, except that one uses a constraint synonym:
type CElt r = (Num r, Eq r)
fooSlow :: (CElt r) => Bar r -> Bar r
{-# INLINABLE fooSlow #-}
fooSlow (C1 u) = either (fromEitherBar . eitherFoo) (fromEitherBar . eitherFoo) u
fooSlow (C2 c) = C2 $ fooSlow c
fooFast :: (Num r, Eq r) => Bar r -> Bar r
{-# INLINABLE fooFast #-}
fooFast (C1 u) = either (fromEitherBar . eitherFoo) (fromEitherBar . eitherFoo) u
fooFast (C2 c) = C2 $ fooFast c
Using criterion, fooSlow
is about 3x slower than fooFast
. Main.hs needs criterion
and deepseq
, but the problem should be evident just from inspecting the core of Bar.hs, which only relies on base
. Code was compiled with GHC-8.0.1 with -O2
.
For some context, in my real code from which this example was extracted, the 'fast' (no constraint synonym) version takes 78 microseconds, while the 'slow' version with the synonym takes 360 microseconds.