0

According to Control.Foldl documentation:

Any lens, traversal, or prism will type-check as a Handler

type Handler a b 
   = forall x. (b -> Constant (Endo x) b) -> a -> Constant (Endo x) a

One might claim that since lens allows for any Functor that is not a Constant only subset of lens should type-check. Why is that statement incorrect?

sevo
  • 4,559
  • 1
  • 15
  • 31

1 Answers1

5

You've got your directions mixed up is all. The optics described there are all of the form

 type Foo s t a b = forall f. SomeConstraints f => (a -> f b)-> (s -> f t)

Small fib, for prisms it's supposed to work with an arbitrary Choice profunctor, but -> is kind of the canonical example of such a structure so we can specialize the prisms to only work across these profunctors. The reason why this process is legal is identical to what we're going to do with f so suspend disbelief for a minute and read on

Now if we instantiate s and t as a and a and b as b then we get

 forall f. SomeConstraints f => (b -> f b) -> (a -> f a)

Now this means that if we have some optic, like a lens, prism, or traversal, we can instantiate its type parameters so that it's almost in the form of a Handler. The only difference is ours is guaranteed to work for any f provided it satisfies the constraints we chose. If we know that Constant (Endo x) satisfies those constraints then we can silently specialize that optic to work only with that f. This is just plain old polymorphic instantiation! And since Constant a is an Functor and an Applicative it will work with any lens or traversal. This implicit subtyping and instantiation is at the heart of making the lens package work, by leaving all of these things transparent Haskell let's us mix and match abstractions and it will automatically settle on the "greatest lower bound" of whatever set of optics we're using.

The whole thing boils down to the fact that in Haskell, if we have e :: forall t. T, then for any appropriately kinded tau we also have e :: [tau/t]T. There are a few wrinkles once we toss in type constraints but over all, it's all just the fact that type application is silent by default in Haskell.

daniel gratzer
  • 52,833
  • 11
  • 94
  • 134