Specifying symbol type for `HasField x r a`

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.

1 Like