Re: [Haskell-cafe] Records in Haskell

2012-03-01 Thread AntC
Evan Laforge qdunkan at gmail.com writes:

 [ ccing the list because the wiki page was flawed and I made a bunch
 of changes, hope you don't mind ]
 

Thanks Evan, I've had a quick read through.

It's a bit difficult to compare to the other proposals.

I can't see discussion of extracting higher-ranked functions and applying them 
in polymorphic contexts. (This is SPJ's `rev` example.)

Putting h-r fields into records is the standard way of emulating object-
oriented style. SPJ's view is that requirement is very important in practice.

(No proposal has a good answer to updating h-r's, which you do discuss.)


Re the cons 1. Still can't have two records with the same field name in the 
same module since it relies on modules for namespacing.

Did you see the DORF precursor page ? 
http://hackage.haskell.org/trac/ghc/wiki/Records/DeclaredOverloadedRecordFields
/NoMonoRecordFields

I tried to figure out if that would help, but I suspect not. (Looking at the 
desugar for `deriving (Lens)`, you need the H98 field selector functions.) 
Then for me, cons 1. is a show-stopper. (I know you think the opposite.)


I also don't see whether you can 'hide' or make abstract the representation of 
a record type, but still allow read-access to (some of) its fields. Suppose a 
malicious client declares a record with field #a. Can you stop them reading 
and/or updating your field #a whilst still letting them see field #b of your 
record type?


With SDNR, is it possibly to define a polymorphic field selector function? I 
suspect no looking at the desugar for `deriving (Lens)`, but perhaps I've mis-
understood. I mean:
get_a r = ?? #a r -- gets the #a field from any record r

This mechanism then supports the idea of 'virtual' fields -- SPJ's example of 
fullName, built from polymorphic firstName and lastName.


[By the way, did you mean to post to the cafe only? Most of the discussion is 
going on on ghc-users.]


AntC


___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Records in Haskell

2012-03-01 Thread Evan Laforge
 Thanks Evan, I've had a quick read through.

Thanks for reading and commenting!

 It's a bit difficult to compare to the other proposals.

 I can't see discussion of extracting higher-ranked functions and applying them
 in polymorphic contexts. (This is SPJ's `rev` example.)

 Putting h-r fields into records is the standard way of emulating object-
 oriented style. SPJ's view is that requirement is very important in 
 practice.

 (No proposal has a good answer to updating h-r's, which you do discuss.)

Yeah, I've never wanted that kind of thing.  I've written in
object-oriented languages so it's not just that I'm not used to the
feature so I don't feel its lack.  And if I did want it, I would
probably not mind falling back to the traditional record syntax,
though I can see how people might find that unsatisfying.  But my
suggestion is meant to solve only the problem of composed record
updates and redundant things in 'Thing.thing_field thing'.  Not
supporting higher-ranked function record fields *only* means that you
can't use this particular convenience to compose updates to a
higher-ranked field.  If you happen to have that particular
intersection of requirements then you'll have to fall back to typing
more things for that particular update.

My motivation is to solve an awkward thing about writing in haskell as
it is, not add a new programming style.

 Re the cons 1. Still can't have two records with the same field name in the
 same module since it relies on modules for namespacing.

 Did you see the DORF precursor page ?
 http://hackage.haskell.org/trac/ghc/wiki/Records/DeclaredOverloadedRecordFields
 /NoMonoRecordFields

 I tried to figure out if that would help, but I suspect not. (Looking at the
 desugar for `deriving (Lens)`, you need the H98 field selector functions.)
 Then for me, cons 1. is a show-stopper. (I know you think the opposite.)

Yeah, I don't think the DORF precursor stuff is related, because it's
all based on typeclasses.  I think there are two places where people
get annoyed about name clashes.  One is where they really want to have
two records with the same field name defined in one module.  The other
is where they are using unqualified imports to shorten names and get a
clash from records in different modules.  Only the former is a
problem, the latter should work just fine with my proposal because ghc
lets you import clashing names as long as you don't call them
unqualified, and SDNR qualifies them for you.

So about the former... I've never had this problem, though the point
about circular imports forcing lots of things into the same module is
well taken, I have experienced that.  In that case: nested modules.
It's an orthogonal feature that can be implemented and enabled
separately, and can be useful in other ways too, and can be
implemented separately.  If we are to retain modules as *the* way to
organize namespaces and visibility then we should think about
fancying-up modules when a namespacing problem comes up.

Otherwise you're talking about putting more than one function into one
symbol, and that's typeclasses, and now you have to think of something
clever to counteract typeclasses' desire to be global (e.g. type
proxies).  Maybe that's forcing typeclasses too far beyond their
power/weight compromise design?

 I also don't see whether you can 'hide' or make abstract the representation of
 a record type, but still allow read-access to (some of) its fields.

If you want a read-only field, then don't export the lens for 'a',
export a normal function for it.  However, it would mean you'd use it
as a normal function, and couldn't pass it to 'get' because it's not a
lens, and couldn't be composed together with lenses.  I'd think it
would be possible to put 'get' and 'set' into different typeclasses
and give ReadLenses only the ReadLens dictionary.  But effectively
we'd need subtyping, so a Lens could be casted automatically to a
ReadLens.  I'm sure it's possible to encode with clever rank2 and
existentials and whatnot, but at that point I'm inclined to say it's
too complicated and not worth it.  Use plain functions.  Since 'get'
turns a lens into a plain function, you can still compose with
'#roField . get (#rwField1 . #rwField2)'.

We could easily support 'get (#roField1 . #roField2)' by doing the
ReadLens thing and putting (-) into ReadLens, it's just combining rw
fields and ro fields into the same composition that would require type
gymnastics.

 Suppose a
 malicious client declares a record with field #a. Can you stop them reading
 and/or updating your field #a whilst still letting them see field #b of your
 record type?

I don't think it's worth designing to support malicious clients, but
if you don't want to allow access to a function or lens or any value,
then don't export it.  #a can't resolve to M.a if M doesn't export
'a'.

 With SDNR, is it possibly to define a polymorphic field selector function? I
 suspect no looking at the desugar for `deriving (Lens)`, but perhaps 

Re: [Haskell-cafe] Records in Haskell

2012-02-27 Thread Evan Laforge
[ ccing the list because the wiki page was flawed and I made a bunch
of changes, hope you don't mind ]

 Thanks Evan, but I think that wiki page isn't doing your
 proposal justice. There seem to be several typos in critical
 places that make it hard to follow (for me at least).

Sorry about the sloppy editing.  I updated it and added more detailed
examples.  I also realized that as stated it didn't quite work for
lens updates, so I extended it a little.

 I think it would really help to include a record decl. to
 show where `a` comes from, especially since you say that
 record syntax doesn't change.

Good point, added.

 Could you explain what the TH does. Perhaps give an example
 of what gets generated from a record decl?

Sure, I added an example of that too.

 And perhaps you could explain what you mean by a type
 directed function? Aren't all overloaded functions type
 directed? Can I have both a `#f` and a `f` in scope? What's
 the difference?

The idea is they're not overloaded functions.  #f is not a symbol that
can be in scope, it's special syntax to go *find* a `f` in some
module.  So `x = #f` is not in conflict with `x = f` provided #f is
desugared to SomeModule.f.  Unless of course the argument is defined
in the current module, in which case it will desugar to plain `f` and
then they will be the same.  Since it's syntax for resolving a name,
assigning it like `#f = xyz` doesn't make sense since you can't put a
qualified name on the left of an `=` sign.

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe