haskellderivingderivingvia# Haskell DerivingVia on multi param type classes with fun deps

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.

Solution

So first of all, let's repeat that the instance you want to be derived for you is this one:

```
instance MyEq (Wrapper Int) Wrapper where
eq (Wrapper t) (Wrapper t') = Wrapper (t == t')
```

I cannot see a way to derive the class in exactly the way you want, because as you observe yourself, this requires you to change both class parameters, but we can currently only derive through the last.

One possibility is to flip the class arguments, so that the "important" class parameter (the one that determines the other) becomes the last, and then tweak the wrapper type you derive via to include some helpful information, like this:

```
class MyEq f a | a -> f where
aeq :: a -> a -> f Bool
```

Function `aeq`

retains the same type, but the class arguments of `MyEq`

are flipped.
Now `Wrapper2`

gets an extra parameter to let us specify the desired value of `f`

when deriving:

```
newtype Wrapper2 (f :: Type -> Type) t = Wrapper2 t
```

Now the instance for `Wrapper2`

can be defined without explicitly specifying `f`

:

```
instance (Eq t, Coercible Bool (f Bool)) => MyEq f (Wrapper2 f t) where
eq (Wrapper2 t) (Wrapper2 t') = coerce (t == t')
```

The extra parameter in `Wrapper2`

is necessary here to satisfy the functional dependency.

Now we can derive the desired instance as follows:

```
deriving via Wrapper2 Wrapper Int instance MyEq Wrapper (Wrapper Int)
```

This works because now, GHC is looking for
an `instance MyEq Wrapper (Wrapper2 Wrapper Int)`

, and this matches the one we have
provided.

You can achieve the same using an associated type:

```
class MyEq a where
type Result a :: Type -> Type
eq :: a -> a -> Result a Bool
```

Same definition of `Wrapper2`

with the extra argument. The instance becomes

```
instance (Eq t, Coercible Bool (f Bool)) => MyEq (Wrapper2 f t) where
type Result (Wrapper2 f t) = f
eq (Wrapper2) (Wrapper2 t') = coerce (t == t')
deriving via Wrapper2 Wrapper Int instance MyEq (Wrapper Int)
```

- Comparing lists in Haskell
- Is there a non-identity monad morphism M ~> M that is monadically natural in M?
- Problem with loading module ‘Distribution.Simple’
- Improving efficiency in Stirling numbers calculation
- Does sequencing an infinite list of IO actions by definition result in a never-ending action? Or is there a way to bail out?
- How to call pgQuery from postgresql-query?
- How to avoid whitespace after a tag (link) in Hamlet templates?
- Understanding type-directed resolution in Haskell with existential types
- Why is seq bad?
- Understanding bind function in Haskell
- How to create route that will trigger on any path in Servant?
- How do I use a global state in WAI middleware?
- nixos 23.11 cabal install mysql-simple problem - "Missing (or bad) C libraries"
- Is there a way to kill all forked threads in a GHCi session without restarting it?
- Why can an invalid list expression such as 2:1 be assigned to a variable, but not printed?
- Iterate over a type level list and call a function based on each type in the list
- How does this solution of Project Euler Problem 27 in the Haskell Wiki work?
- Why `Monad` is required to use `pure`?
- Can't do partial function definitions in GHCi
- recommended way to convert Double -> Float in Haskell
- Haskell profiling understanding cost centre summary for anonymous lambda
- Why is Haskell fully declarative?
- GHC Generating Redundant Core Operations
- Question about Event firing in reflex-frp
- Using Haskell's "Maybe", type declarations
- How can I elegantly invert a Map's keys and values?
- Why there is no output for wrapped IO in Haskell?
- What are the definitions of Weather and Memory in xmobar repo?
- Serializing a Data.Text value to a ByteString without unnecessary \NUL bytes
- Using Haskell with VS Code