
Simon Peyton-Jones
writes: ...; it’s a tradeoff between polymorphism and overloading.
Hah! my post crossed with Simon's. This time I'll be succinct. There's **three** alternatives. ...
data R a = MkR { foo :: a -> a } data S = MkS { bar :: forall b. b -> b }
Try Plan C: use a cleverer (associated) type function class Has r f t where type GetResult r f t :: * -- ?? default to t getFld :: r -> GetResult r f t instance (t ~ a->a) => Has (R a) “foo” t where type GetResult (R a) "foo" t = a -> a -- ?? ignore t getFld ... instance (t ~ b->b) => Has S “bar” t where type GetResult S "bar" t = t -- 'improved' t getFld ... In the 'chained' accessors that Edward raises, I think the presence of the type function 'fools' type inference into thinking there's a dependency. So (foo . bar) has type (and abusing notation): ( Has r "bar" t_bar, Has (GetResult r "bar" t_bar) "foo" t_foo ) => r -> (GetResult (GetResult r "bar" t_bar) "foo" t_foo)