I'm trying to use DerivingVia
to cut the boilerplate on instance definitions for a multi parameter type class with functional dependencies.
I have these types and class:
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE DerivingVia #-}
newtype Wrapper t = Wrapper t
newtype Wrapper2 t = Wrapper2 t
class MyEq a f | a -> f where
eq :: a -> a -> f Bool
-- Instance for 'Wrapper2'
instance Eq t => MyEq (Wrapper2 t) Wrapper2 where
eq (Wrapper2 t) (Wrapper2 t') = Wrapper2 (t == t')
I want to derive MyEq (Wrapper Int) Wrapper
using deriving via
.
My first attempt was to use:
deriving via Wrapper2 instance MyEq (Wrapper Int) Wrapper
As discussed in the paper section 6.2, https://www.kosmikus.org/DerivingVia/deriving-via-paper.pdf, this looks for a MyEq (Wrapper Int) Wrapper2
instance, the second argument was "changed" but the first one is still Wrapper Int
.
Obviously instance MyEq (Wrapper Int) Wrapper2
does not exists because I implemented instance MyEq (Wrapper2 Int) Wrapper2
.
I cannot "cheat" by creating (see Wrapper
as first type argument):
-- Instance for 'Wrapper2'
instance Eq t => MyEq (Wrapper t) Wrapper2 where
eq (Wrapper2 t) (Wrapper2 t') = Wrapper2 (t == t')
Because in this case the functional dependency Wrapper t -> Wrapper2
is not respected.
I can easily solve the issue by rewriting eq :: f a -> f a -> f Bool
and removing the functional dependency, but I'd like to avoid changing this API.
UndecidableInstances
. – Hombre