I'm also rather worried, looking over the IV proposal, that it just doesn't actually work.

We actually tried the code under "Haskell 98 records" back when Gundry first started his proposal and it fell apart when you went to compose them.

A fundep/class associated type in the class is a stronger constraint that a type equality defined on an individual instance.

I don't see how

@foo . @bar . @baz

(or #foo . #bar . #baz as would be written under the concrete proposal on the wiki) 

is ever supposed to figure out the intermediate types when working polymorphically in the data type involved. 

What happens when the type of that chain of accessors is left to inference? You get stuck wallowing in AllowAmbiguousTypes territory:

(#foo . #bar . #baz) :: (IV "foo" (c -> d), IV "bar" (b -> c), IV "baz" (a -> b)) => a -> d

has a variables 'b' and 'c' that don't occur on the right hand side, and which are only determinable by knowing that the instances you expect to see look something like:
instance (a ~ Bool) => IV "x" (S -> a) where
  iv (MkS x) = x
but that is too weak to figure out that "S" determines "a" unless S is already known, even if we just limit ourselves to field accessors as functions.

-Edward


On Mon, Jan 26, 2015 at 7:43 PM, Edward Kmett <ekmett@gmail.com> wrote:
On Mon, Jan 26, 2015 at 4:41 PM, Simon Peyton Jones <simonpj@microsoft.com> wrote:

Personally, I don't like the sigil mangled version at all. 

You don’t comment on the relationship with implicit parameters.  Are they ok with sigils?


I don't have too many opinions about implicit parameters, but they don't really see a lot of use, which makes me somewhat leery of copying the pattern. ;)

If it is then further encumbered by a combinator it is now several symbols longer at every single use site than other alternatives put forth in this thread. =(

No, as Nikita says, under the “Redesign” proposal it would be #bar . #baz

The problem is that if you make #bar an instance of Category so that it can use (.) then it will fail to allow type changing re-assignment.
 

The import Field trick is magic, yes, but it has the benefit of being the first approach I've seen where the resulting syntax can be as light as what the user can generate by hand today.

That’s why I added it to the “Redesign” page. It seems viable to me; a clever idea, thank you.  Still, personally I prefer #x because of the link with implicit parameters.  It would be interesting to know what others think.

Admittedly @bar . @baz has the benefit that it introduces no namespacing conflicts at all. 

If we really had to go with some kind of sigil based solution, I _could_ rally behind that one, but I do like it a lot less than the import trick, if only because the import trick gets rid of that last '@' and space we have on every accessor and you have to admit that the existing

foo^.bar.baz.quux 

idiom reads a lot more cleanly than

foo ^. @bar . @baz . @quux

ever can.

(I used @foo above because it avoids any potential conflict with existing user code as @ isn't a legal operator)

I'm confess, I, like many in this thread, am less than comfortable with the notion of bringing chunks of lens into base. Frankly, I'd casually dismissed such concerns as a job for Haskell 2025. ;) However, I've been trying to consider it with an open mind here, because the alternatives proposed thus far lock in uglier code than the status quo with more limitations while simultaneously being harder to explain.

I don’t think anyone is suggesting adding any of lens are they?  Which bits did you think were being suggested for addition?

I was mostly referring to the use of the (a -> f b) -> s -> f t form. 

Note: once you start using a data-type then (.) necessarily fails to allow you to ever do type changing assignment, due to the shape of Category, or you have to use yet another operator, so that snippet cannot work without giving up something we can do today. OTOH: Using the lens-style story, no types are needed here that isn't already available in base and, done right, no existing operators need be stolen from the user, and type changing assignment is trivial.

I’m afraid I couldn’t understand this paragraph at all.  Perhaps some examples would help, to illustrate 

what you mean?

I was writing that paragraph in response to your query if it'd make sense to have the @foo return some data type: It comes at a rather high cost.
 
Lens gets away with using (.) to compose because its really using functions, with a funny mapM-like shape (a -> f b) -> (s -> f t) is still a function on the outside, it just happens to have a (co)domain that also looks like a function (a -> f b). 

If we make the outside type constructor a data type with its own Category instance, and just go `Accessor s a` then it either loses its ability to change out types in s  -- e.g. change out the type of the second member in a pair, or it loses its ability to compose.

We gave up the latter to make Gundry's proposal work as we were forced into that shape by trying to return a combinators that could be overloaded to act as an existing accessor function.

To keep categorical composition for the accessor, you might at first think we can use a product kind or something to get Accessor '(s,t) '(a,b) with both indices but that gets stuck when you go to define `id`, so necessarily such a version of things winds up needing its own set of combinators.

-Edward