GHC support for the new "record" package

Simon Peyton Jones simonpj at microsoft.com
Mon Feb 2 14:16:49 UTC 2015


In scala Julien Truffaut has a library called Monocle, which aspires to be a port of the ideas of lens to Scala. Due to the vagaries of the language the only option they have open to them is to implement things the way you are looking at exploring here. It doesn't work out well. Vastly more effort yields a library full of boilerplate that handles a much smaller scope and yields no insight into why these things are related.

I dispute nothing that you say.  But I don’t think a Scala failure should discourage us.  Scala doesn’t let you abstract over higher kinds (or at least it’s very tricky because of variance); and I’m pretty sure it doesn’t let you abstract over constraints.    I’m not saying that these are enough; just that it shouldn’t necessarily discourage us too much.

On one point:
Isomorphisms and prisms overload the shape to look more like p a (f b) -> p s (f t), rather than (a -> f b) -> s -> f t.  Indexing, which matters for folding and traversing over containers with keys overloads with a shape like p a (f b) -> s -> f t
So maybe we’d need
            newtype SuperLens c p q s t a b = SL (forall f. c f => p a (f b) -> q s (f t))

You may say that the SuperLens newtype it is “dangling there”, and you might be right, but it remains something that can drive a type-class story.

You may well be right; but I’d be very interested in an investigation that followed it through.  (Dan’s observations about And are well taken.)

Simon

From: Edward Kmett [mailto:ekmett at gmail.com]
Sent: 29 January 2015 03:52
To: Simon Peyton Jones
Cc: Dan Doel; ghc-devs at haskell.org
Subject: Re: GHC support for the new "record" package

Alas, the 'f' isn't the only thing in the lens library signatures that gets overloaded in practice.


By the time you reach that level of generality, and add type-changing, the newtype is sort of just dangling there actively getting in the way and providing no actual encapsulation.

Now, you could make up a bunch of individual ad hoc data types for all the different lens types we happen to know about today.

However, it is deeply insightful that it is the form that lenses take that let us _find_ all the different lens-likes that we use today.

Half of them we had no idea were out there until we spent time exploring the impact of the design we have.

Switching to a representation where these things arise from O(n^2) ad-hoc rules rather than the existing relationships between mostly "common sense" classes seems like a poor trade.

In scala Julien Truffaut has a library called Monocle, which aspires to be a port of the ideas of lens to Scala. Due to the vagaries of the language the only option they have open to them is to implement things the way you are looking at exploring here. It doesn't work out well. Vastly more effort yields a library full of boilerplate that handles a much smaller scope and yields no insight into why these things are related.

-Edward


On Wed, Jan 28, 2015 at 5:32 AM, Simon Peyton Jones <simonpj at microsoft.com<mailto:simonpj at microsoft.com>> wrote:
As soon as you have a distinct Lens type, and use something Category-like for composition, you are limiting yourself to composing two lenses to get back a lens (barring a terrible mptc 'solution'). And that is weak. The only reason I (personally) think lens pulls its weight, and is worth using (unlike every prior lens library, which I never bothered with), is the ability for lenses, prisms, ismorphisms, traversals, folds, etc. to properly degrade to one another and compose automatically.​
Aha.  I keep asking whether it’s just the cute ability to re-use (.) that justifies the lack of abstraction in the Lens type.  But Dan’s comment has made me remember something from my own talk on the subject.  Here are the types of lenses and traversals (2-parameter versions):


type Lens’      s a = forall f. Functor f

                           => (a -> f a) -> (s -> f s)

type Traversal’ s a = forall f. Applicative f

                           => (a -> f a) -> (s -> f s)

Suppose we have

ln1 :: Lens'      s1 s2

tr1 :: Traversal' s1 s2

ln2 :: Lens'      s2 a

tr2 :: Traversal' s2 a

Now these compositions are all well typed

ln1 . ln2 :: Lens' s1 a

tr1 . tr2 :: Traversal' s1 a

tr1 . ln2 :: Traversal' s1 a

ln1 . tr2 :: Traversal' s1 a

which is quite remarkable.  If Lens’ and Traversal’ were newtypes, you’d need four different operators.  (I think that what Dan means by “a terrible mptc solution” is trying to overload those four operators into one.)

I don’t know if this exhausts the reasons that lenses are not abstract.  I would love to know more, explained in a smilar style.

Incidentally has anyone explored this?


newtype PolyLens c s a = PL (forall f. c f => (a -> f a) -> s -> f s)


I’ve just abstracted over the Functor/Applicative part, so that Lens’ and Traversal’ are both PolyLenses.  Now perhaps we can do (.), with a type like


(.) :: PolyLens c1 s1 s2 -> PolyLens c2 s2 a -> PolyLens (And c1 c2) s1 a

where And is a type function


type instance And Functor Applicative = Applicative
etc

I have no idea whether this could be made to work out, but it seems like an obvious avenue so I wonder if anyone has explored it.

Simon

From: Dan Doel [mailto:dan.doel at gmail.com<mailto:dan.doel at gmail.com>]
Sent: 28 January 2015 00:27
To: Edward Kmett
Cc: Simon Peyton Jones; ghc-devs at haskell.org<mailto:ghc-devs at haskell.org>
Subject: Re: GHC support for the new "record" package

On Tue, Jan 27, 2015 at 6:47 PM, Edward Kmett <ekmett at gmail.com<mailto:ekmett at gmail.com>> wrote:

This works great for lenses that don't let you change types.

​This is not the only restriction required for this to be an acceptable solution.
As soon as you have a distinct Lens type, and use something Category-like for composition, you are limiting yourself to composing two lenses to get back a lens (barring a terrible mptc 'solution'). And that is weak. The only reason I (personally) think lens pulls its weight, and is worth using (unlike every prior lens library, which I never bothered with), is the ability for lenses, prisms, ismorphisms, traversals, folds, etc. to properly degrade to one another and compose automatically. So if we're settling on a nominal Lens type in a proposal, then it is automatically only good for one thing to me: defining values of the better lens type.​
-- Dan

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.haskell.org/pipermail/ghc-devs/attachments/20150202/1d221ce6/attachment-0001.html>


More information about the ghc-devs mailing list