Using Deriving Via with Phantom Types

Apologies for the long repro but I haven't been able to make it any shorter. The following code compiles fine until the last line:

``````{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, UndecidableInstances #-}
{-# LANGUAGE DerivingVia, DerivingStrategies, StandaloneDeriving #-}
{-# LANGUAGE ScopedTypeVariables #-}

module Repro where

import Prelude hiding ((+))

(+) :: a -> a -> a

data Vector2D u = Vector2D {
x :: u,
y :: u
}

addVector2 :: (Additive a) => Vector2D a -> Vector2D a -> Vector2D a
addVector2 Vector2D { x = x1, y = y1 } (Vector2D { x = x2, y = y2 }) =
Vector2D { x = x1 + x2, y = y1 + y2 }

newtype Phantom1 d a = Phantom1 (Vector2D a) --Axial

deriving via (Vector2D a) instance forall d . (Additive a) => (Additive (Phantom1 d a))

data Via a b = Via a

class IsoEvidence a b where
convertTo :: a -> b
convertFrom :: b -> a

instance forall a b . (IsoEvidence a b, Additive b) => (Additive (Via a b)) where
(Via x) + (Via y) = Via \$ convertFrom \$ (convertTo x :: b) + (convertTo y :: b)

newtype Phantom2 d a = Phantom2 (Vector2D a) --Offset

instance (IsoEvidence (Phantom1 d a) (Phantom2 d a)) where
convertTo (Phantom1 x) = Phantom2 x
convertFrom (Phantom2 x) = Phantom1 x

deriving via (Via (Phantom2 d a) (Phantom1 d a))
instance (Additive a, IsoEvidence (Phantom1 d a) (Phantom2 d a)) =>
``````

After that I get the following error:

• Couldn't match representation of type `Vector2D a` with that of `Via (Phantom2 d a) (Phantom1 d a)`

Which seems to be saying it can't coerce "Via &c" to "Vector2D a", which is odd because it's literally a newtype two levels deep and that works fine.

What am I doing wrong here?

Solution

• `DerivingVia` works through newtypes, but you wrote

``````data Via a b = Via a   -- should be newtype
``````