May I suggest something for a syntax (as an option, sorry if it's silly or
not related)? I really don't like neither @ or # because they seem too
hacky, meanwhile GHC already has an accessor syntax with braces { and },
so, might it be an option to have something like:
```
data Foo = Foo { val :: Int }
data Bar = Bar { foo :: Foo }
main = do
let bar = Bar (Foo 10)
print bar{foo{val}}
let bar' = bar{foo{val}=10}
return ()
```
I think this syntax is 100% understandable for a newbie. Not sure how is
it related to lenses though.
What do you think?
If the level of complaints I received when I stole (#) for use in lens is
any indication, er.. it is in very wide use. It was by far the most
contentious operator I grabbed. ;)
It seems to me that I'd not be in a hurry to both break existing code and
pay a long term syntactic cost when we have options on the table that don't
require either, the magic Field module approach that both Eric and I
appear to have arrived at independently side-steps this issue nicely and
appears to result in a better user experience.
Keep in mind, one source of objections to operator-based sigils is that if
you put an sigil at the start of a lens the tax isn't one character but
two, there is a space you now need to avoid (.#) when chaining these
things. foo.bar vs. #foo . #bar and the latter will always be uglier.
The `import Field (...)` approach results in users never having to pay more
syntactically than with options they have available to them now, and being
class based is even beneficial to folks who don't use Nikita's records.
-Edward
On Fri, Jan 23, 2015 at 5:47 PM, Greg Weber g...@gregweber.info wrote:
If we only add syntax when the language extension is used then we are not
clobbering everyone. # is not that common of an operator. I would much
rather upset a few people by taking that operator back when they opt-in to
turning the extension on than having a worse records implementation.
On Fri, Jan 23, 2015 at 2:23 PM, Edward Kmett ekm...@gmail.com wrote:
On Fri, Jan 23, 2015 at 5:06 PM, Adam Gundry a...@well-typed.com wrote:
Thanks for the feedback, Iavor!
On 23/01/15 19:30, Iavor Diatchki wrote:
2. I would propose that we simplify things further, and provide just
one
class for overloading:
class Field (name :: Symbol)
rec rec'
field field'
| name rec - field
, name rec'- field'
, name rec field' - rec'
, name rec' field - rec
where
field :: Functor f = Proxy name - (field - f field') -
(rec - f rec')
I don't think we need to go into lenses at all, the `field` method
simply provides a functorial
update function similar to `mapM`. Of course, one could use the
`lens`
library to
get more functionality but this is entirely up to the programmer.
When the ORF extension is enabled, GHC should simply generate an
instance of the class,
in a similar way to what the lens library does
3. I like the idea of `#x` desugaring into `field (Proxy :: Proxy x)`,
but I don't like the concrete symbol choice:
- # is a valid operator and a bunch of libraries use it, so it won't
be compatible with existing code.
Ah. I didn't realise that, but assumed it was safe behind -XMagicHash.
Yes, that's no good.
- @x might be a better choice; then you could write things like:
view @x rec
set @x 3rec
over @x (+2) rec
This could work, though it has the downside that we've been informally
using @ for explicit type application for a long time! Does anyone know
what the status of the proposed ExplicitTypeApplication extension is?
I'll confess I've been keen on stealing @foo for the purpose of (Proxy ::
Proxy foo) or (Proxy :: Proxy foo) from the type application stuff for a
long time -- primarily because I remain rather dubious about how well the
type application stuff can work, once you take a type and it goes through a
usage/generalization cycle, the order of the types you can apply gets all
jumbled up, making type application very difficult to actually use. Proxies
on the other hand remain stable. I realize that I'm probably on the losing
side of that debate, however. But I think it is fair to say that that
little bit of dangling syntax will be a bone that is heavily fought over. ;)
- another nice idea (due to Eric Mertens, aka glguy), which allows us
to avoid additional special syntax is as follows:
- instead of using special syntax, reuse the module system
- designate a magic module name (e.g., GHC.Records)
- when the renamer sees a name imported from that module, it
resolves the name by desugaring it into whatever we want
- For example, if `GHC.Records.x` desugars into `field (Proxy ::
Proxy x)`, we could write things like this:
import GHC.Records as R
view R.x rec
set R.x 3rec
over R.x (+2) rec
Interesting; I think Edward