Hi Luciano,
that’s a very interesting problem. The solution mostly involves sprinkling a few more types across your code. Despite that, you will still need to enable the AllowAmbiguousTypes
language extension because the type parameter f
only appears within the type class constraints.
First of all, you need to tell the compiler that you want to access the x
field in updateInner
's setField
and getField
:
updateInner : forall x f. (Functor f, HasField x Outer (f Inner)) => (Inner -> Inner) -> Outer -> Outer
updateInner fi o = setField @x (fmap fi (getField @x o)) o
Notice how we added @x
type applications to setField
and getField
. For x
to be in scope at these places, we need to explicitly introduce it (and also f
) using the forall x f.
abstraction in the type signature of updateInner
. Having the x
as the first type parameter makes call sites more convenient since you only have to provide the field name, as in updateInner @"a"
, and don’t need to provide the functor, for field a
it would be Optional
here. Thus, if we assume type Inner = Int
, we can use updateInner
like
incrementA : Outer -> Outer
incrementA outer = updateInner @"a" (\i -> i + 1) outer
I hope that solves your problem,
Martin.