I'm unable to automatically derive instances using DerivingVia
on any type that uses types from optics-core
like Prism'
; the error I get from compiler is:
src/Main.hs:24:13-19: error:
• Couldn't match type ‘Foo’ with ‘Stringable Foo’
arising from the coercion of the method ‘mkPrism’
from type ‘MyPrism (Stringable Foo)’ to type ‘MyPrism Foo’
• When deriving the instance for (MkPrism Foo)
|
24 | deriving (MkPrism) via (Stringable Foo)
| ^^^^^^^
The type in question is:
newtype MyPrism a
= MyPrism (Prism' String a)
The compilation succeeds if I replace the Prism'
type with its underlying representation, viz.:
newtype MyPrism a
= MyPrism (a -> String, String -> Maybe a)
- Why do I see coercion issues when using
Prism'
? Is it because theOptic
constructor is not exported by the package? - What is the usual way to solve this?
You can see the full program to reproduce this here: https://github.com/srid/q-optics-coercion/blob/f1e3df5e1c5c0e4a51eacb6439fb8c627e4c7bd5/src/Main.hs ... if you have Nix installed, you can run bin/run
in this repo.
EDIT: Once I import Optics.Internal.Optic
, the error message becomes:
src/Main.hs:25:13-19: error:
• Couldn't match representation of type ‘p i Foo Foo’
with that of ‘p i (Stringable Foo) (Stringable Foo)’
arising from the coercion of the method ‘mkPrism’
from type ‘MyPrism (Stringable Foo)’ to type ‘MyPrism Foo’
• When deriving the instance for (MkPrism Foo)
|
25 | deriving (MkPrism) via (Stringable Foo)
|
Generally speaking, profunctor optics (such as those used in the
lens
andoptics
packages) aren't directly coercible. Roughly speaking, the internal representation of a prism is something like:(Well, at least that's what it is for
Control.Lens
. ForOptics.Core
, it might be a little more complicated.)The problem here is that
a
ands
appear as parameters to higher-kinded type variables (f
andp
) in this type. As a result, their "roles" are nominal (see the Role Inference section in the GHC manual for an explanation why), and these nominal roles prevent direct coercion.Fortunately, there are some functions in
Optics.Coerce
that are designed to deal with this. You won't be able to derive aMyPrism
type directly via the newtype, but you should be able to write: