Eq1, Ord1, Show1: move from eq1, compare1, showsPrec1 to liftEq, liftCompare, liftShowsPrec
Ryan Scott
ryan.gl.scott at gmail.com
Mon Jan 11 15:00:44 UTC 2016
- Previous message: Eq1, Ord1, Show1: move from eq1, compare1, showsPrec1 to liftEq, liftCompare, liftShowsPrec
- Next message: Eq1, Ord1, Show1: move from eq1, compare1, showsPrec1 to liftEq, liftCompare, liftShowsPrec
- Messages sorted by:
[ date ]
[ thread ]
[ subject ]
[ author ]
> In transformers-0.5 it seems that I have to implement Eq1, Ord1, Show1 instances manually.
For better or worse, that is indeed the case. Before,
Eq1/Ord1/Read1/Show1 relied on the type argument having an implicit
dictionary to use, which is why you could get away with piggybacking
off of your existing Eq/Ord/Read/Show instances. Now, Eq1, Eq2, and
friends rely on explicit dictionary passing, so they're strictly more
powerful than Eq et al.
> Is there some assistance to define eq1 and compare1 for an ADT?
At the moment, no. Sometime in the future, I want to do two things
which should make the situation a little better:
1. Write a language extension to derive Eq1/Eq2/etc. It definitely
won't be making it into GHC 8.0 due to time constraints, plus I need
to propose a design. And...
2. ...I should write a Template Haskell shim which implements the
proposed design. I already have a package called deriving-compat [1]
which has done this (but only for recent changes to -XDeriveFoldable),
so that would probably be a logical place to put it.
Until then, if you need to hand-roll Eq1/Eq2/etc. instances that align
with your Eq instances, I'd recommend copying the output of ghc
-ddump-deriv, copying the generated instances, and replacing the
necessary calls with dictionary arguments. For example, given this
instance:
data Example a = Example Int a deriving Eq
Compiling with ghc -ddump-deriv gives you this (after some code cleanup):
instance Eq a => Eq (Example a) where
Example i1 a1 == Example i2 a2 = i1 == i2 && a1 == a2
e1 /= e2 = not (e1 == e2)
Then, you can create an Eq1 instance with some minor adjustments:
instance Eq1 Example where
liftEq eq (Example i1 a1) (Example i2 a2) = i1 == i2 && eq a1 a2
> What are the use cases where eq1 was not powerful enough and liftEq is needed?
The previous type signature of Data.Functor.Classes in
transformers-0.4 resulted in some awkward instances, a prime example
being found in Data.Functor.Compose:
import Data.Functor.Classes(Eq1(..))
newtype Compose f g a = Compose (f (g a))
instance (Functor f, Eq1 f, Eq1 g, Eq a) => Eq (Compose f g a) where
Compose x == Compose y = eq1 (fmap Apply x) (fmap Apply y)
instance (Functor f, Eq1 f, Eq1 g) => Eq1 (Compose f g) where eq1 = (==)
newtype Apply g a = Apply (g a)
instance (Eq1 g, Eq a) => Eq (Apply g a) where
Apply x == Apply y = eq1 x y
This is a super-kludgey instance because it requires f to be a Functor
instance. In general, having these Functor constraints pop up
everywhere results in less efficient instances, and it won't work at
all for many GADT-like constructions that can't have legal Functor
instances. With the new API, there is no need for these Functor
constraints:
import Data.Functor.Classes(Eq1(..))
newtype Compose f g a = Compose (f (g a))
instance (Eq1 f, Eq1 g) => Eq1 (Compose f g) where
liftEq eq (Compose x) (Compose y) = liftEq (liftEq eq) x y
Ryan S.
-----
[1] http://hackage.haskell.org/package/deriving-compat
- Previous message: Eq1, Ord1, Show1: move from eq1, compare1, showsPrec1 to liftEq, liftCompare, liftShowsPrec
- Next message: Eq1, Ord1, Show1: move from eq1, compare1, showsPrec1 to liftEq, liftCompare, liftShowsPrec
- Messages sorted by:
[ date ]
[ thread ]
[ subject ]
[ author ]
More information about the Libraries
mailing list