Gábor Lehel illissius at gmail.com writes:
..., but DORF actually requires less type system magic than
SORF, and also already has a working prototype implementation, ...
... My main complaint against DORF is
that having to write fieldLabel declarations for every field you want
to use is onerous. ...
(Here's a possible way to reduce the need for declarations,
for non-sharing fields; also avoid the fieldLabel new decl.)
SPJ introduced some fancy type-handling for higher-ranked fields. But still it
only helped in accessing a H-R field, not updating it.
If we accept that updating H-R fields in liberated-namespace records is not
possible, can we simplify the implementation? I think so. Here's what I'd call
a well-principled work-round (not a hack, but then neither a solution).
(I'm showing it in DORF-like style, but I think it would work equally in SORF
style with Stringy Kinds. The advantage of showing DORF is that we can try it -
- which I've done.)
You write:
data HR = HR{ objectId :: ObjectId -- type Pun
, rev :: forall a. [a] - [a] } -- SPJ's example
sharing (ObjectId) deriving (...) -- new syntax
-- this decl is not sharing `rev`, so no further code needed
-- HR is sharing objectId, so you need a field Label in scope:
-- probably you're already declaring newtypes/data
newtype ObjectId = ObjectId Int -- declaring a field
deriving (Has, ... ) -- `Has` makes it a label
Field access can be polymorphic:
f :: HR - ([Bool], [Char])
f r = (r.rev [True], r.rev hello)
Record update looks like:
... myHR{ rev = Rev reverse } ... -- annoying pun
But perhaps we could support sugar for it:
... myHR{ Rev reverse } ... -- fewer keystrokes!
The HR decl desugars to:
newtype Rev = Rev (forall a. [a] - [a])-- newtype punning
data HR = HR{ objectId :: ObjectId, rev :: Rev }
rev :: HR - (forall a. [a] - [a]) -- monotype field selector
rev r = let (Rev fn) = get r (undefined :: Rev) in fn
instance Has HR Revwhere
get HR{ rev } _ = rev -- have to wrap the fn
set (Rev fn) HR{ .. } = HR{ rev = (Rev fn) }
type instance FieldTy HR Rev = Rev -- have to wrap this
-- else update don't work
So I've simplified `Has` to two type arguments (like the more naieve form SPJ
considers then rejects). And used the field's type itself as the index (so
that we're punning on the field name):
class Has r fld where
get :: r - fld - FieldTy r fld
set :: fld - r - SetTy r fld -- for type change update
For the record type's `sharing` fields we desugar to:
instance Has HR ObjectId where
get HR{ objectId } _ = objectId -- yeah dull, dull
set x HR{ .. } = HR{ objectId = x, .. }
and the `deriving (Has)` on the newtype or data desugars to:
objectId :: {Has r ObjectId} = r - ObjectId -- overloaded record
objectId r = get r (undefined :: ObjectId) -- selector
type instance FieldTy r ObjectId = ObjectId -- not parametric
AntC
___
Glasgow-haskell-users mailing list
Glasgow-haskell-users@haskell.org
http://www.haskell.org/mailman/listinfo/glasgow-haskell-users