8

A recent question led me to wonder how to convert a

forall f . Functor f => [LensLike f s t a b]

into a

[ReifiedLens s t a b]

There's an easy way to do it really slowly, by indexing into the list with !!, but it's quite incredibly inefficient. It feels like there should be enough parametricity to pull a trick similar to the one used in reflection, but I can't seem to figure anything out. Is it possible to do this efficiently at all?

11
  • 2
    I don't think this is even possible. We'd have to go (operationally) from Functor f -> [LensLike f s t a b] to [Functor f -> LensLike f s t a b]. We need to pass in a Functor f to pull out a list to begin with, and there isn't one around. Commented Oct 12, 2015 at 21:33
  • 2
    @AndrásKovács Perhaps we can use a parametricity argument to convince ourselves that functions of type Functor f -> [LensLike f s t a b] must choose the length of their result list without inspecting the Functor f argument in a meaningful way. Then it's easy to get the rest of the way from there. (Of course this claim is clearly not true of functions of type Functor F -> [LensLike F s t a b] for some particular F.) Commented Oct 12, 2015 at 21:35
  • @AndrásKovacs, that was my fear. We'd need some kind of "superfunctor" dictionary we could pass in that would magically be able to take on the identity of any other Functor dictionary. Commented Oct 12, 2015 at 21:36
  • 1
    I'd like to point out for the specific case of lenses, you can use ALens instead of ReifiedLens. I'm wondering if there's a similar trick that works generally... Commented Oct 12, 2015 at 22:29
  • 2
    @chi, something like this perhaps. Commented Oct 12, 2015 at 23:35

1 Answer 1

5

Testing out my idea in the comments, you can in fact write this directly by passing through ALens:

convert :: (forall f. Functor f => [LensLike f s t a b]) -> [ReifiedLens s t a b]
convert ls = [Lens (cloneLens l) | l <- ls]

ALens is based on the Pretext functor:

type ALens s t a b = LensLike (Pretext (->) a b) s t a b

newtype Pretext p a b t = Pretext { runPretext :: forall f. Functor f => p a (f b) -> f t }

This allows using a single Functor to represent all of them, at least for lens usage.

I'm still wondering whether there's a method that works generally and not just for lenses.

Sign up to request clarification or add additional context in comments.

1 Comment

I still find Pretext baffling. As applied to (->), I can sort of see it as a partially applied lens, but its utility and generality still confuse me.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.