#3632: lift restrictions on records with existential fields, especially in the
presence of class constraints
----------------------------------------------------+-----------------------
Reporter: eflister | Owner:
Type: feature request | Status: new
Priority: normal | Milestone:
Component: Compiler | Version: 6.10.4
Severity: normal | Resolution:
Keywords: existential records accessor update | Difficulty: Unknown
Testcase: | Os:
Unknown/Multiple
Architecture: Unknown/Multiple |
----------------------------------------------------+-----------------------
Changes (by simonpj):
* difficulty: => Unknown
Old description:
> the attached file demos the use of a record with an existential field
> with a class constraint. it shows several cases where lifting the
> current restrictions on accessing and updating this field would be both
> well-defined and useful.
>
> here is the record definition; the dur field is existential, but
> constrained to be in class NoteDur.
>
> {{{
> data Note = forall x . NoteDur x => Note {
> midiNum :: Int -- 0-255
> , vel :: Int -- 0-255
> , chan :: Int -- 0-15
> , measure :: Integral a => a
> , beat :: Int
> , subdiv :: RealFrac a => a -- % of beat
> , dur :: x
> }
> }}}
>
> here is a walk through of places in the code where the current
> restrictions are unnecessary and intrusive:
>
> lines 64-95 -- these functions wouldn't be necessary if record update
> syntax were enabled for both existential and non-existential fields. i
> know 6.12 introduces it for non-existentials, but i don't see why it
> isn't also possible for existential fields (even without a class
> constraint). lines 33-35 and 60 show how much nicer it is to use regular
> updater syntax in this case.
>
> the same is true for existential accessors when there is a class
> constraint -- there's no need to restrict this situation because the
> accessor can have type:
> fieldName :: (SomeClass x) => Record -> x
> line 142 shows a case where this would be very nice to have.
>
> line 100 + 107 -- the foralls could be implicit (maybe offer an extention
> that would allow them to be implicit)
>
> lines 134-136 compared to 138-139 show how additional factoring could be
> achieved if one were allowed to pattern match on the type of an
> existential with class constraints.
>
> lines 124-127 show how it would be nice to have existential classes
>
> lastly, allow curried updater functions:
> (rec {field = }) 5
> instead of
> (\x -> (rec {field = x})) 5
New description:
the attached file demos the use of a record with an existential field with
a class constraint. it shows several cases where lifting the current
restrictions on accessing and updating this field would be both well-
defined and useful.
here is the record definition; the dur field is existential, but
constrained to be in class NoteDur.
{{{
data Note = forall x . NoteDur x => Note {
midiNum :: Int -- 0-255
, vel :: Int -- 0-255
, chan :: Int -- 0-15
, measure :: Integral a => a
, beat :: Int
, subdiv :: RealFrac a => a -- % of beat
, dur :: x
}
}}}
here is a walk through of places in the code where the current
restrictions are unnecessary and intrusive:
1. lines 64-95 -- these functions wouldn't be necessary if record update
syntax were enabled for both existential and non-existential fields. i
know 6.12 introduces it for non-existentials, but i don't see why it isn't
also possible for existential fields (even without a class constraint).
lines 33-35 and 60 show how much nicer it is to use regular updater syntax
in this case.
2. Line 142. The same is true for existential accessors when there is a
class constraint -- there's no need to restrict this situation because the
accessor can have type:
{{{
fieldName :: (SomeClass x) => Record -> x
}}}
line 142 shows a case where this would be very nice to have.
3. line 100 + 107 -- the foralls could be implicit (maybe offer an
extention that would allow them to be implicit)
4. lines 134-136 compared to 138-139 show how additional factoring could
be achieved if one were allowed to pattern match on the type of an
existential with class constraints.
5. lines 124-127 show how it would be nice to have existential classes
6. lastly, allow curried updater functions: `(rec {field = }) 5` instead
of `(\x -> (rec {field = x})) 5`
Comment:
Brief responses.
1. It's not all that simple; if a record had two existential fields (e.g.
`dur1,dur2::x`), you'd have to update them both simultaneously. But the
rule could, and probably should, be: if the desugared version typechecks,
so should the record-update form. So, yes.
2. Either I misunderstand you, or this is unsound. Remember, the type
'x' is unknown, so it can't be supplied by the caller. So, as far as I can
see this is a non-starter.
3. This is already possible
{{{
data ModDur where
Dotted :: NoteDur x => x -> ModDur
Triplet :: DurBase -> ModDur
}}}
4. I don't understand this at all. In your example
{{{
quarters (x y) = quarters y * case x of
}}}
what are you expecting 'x' to be bound to? The constructor itself?
If so, you are way beyond Haskell. Check out [http://www-
staff.it.uts.edu.au/~cbj/patterns/ Barry Jay's excellent work].
5. I have no idea what you mean here.
6. Quite possible, along the lines of tuple sections. The
complexity/benefit ratio is debatable; my nose says "not quite worth it"
but I'd be interested to know what others think.
So for me (1) is the thing that would be worth fixing. I remember
spending a while thinking about doing this a year ago, but I didn't do it
for some reason. I think it might have been to do with generating
sensible error messages.
Simon
--
Ticket URL: <http://hackage.haskell.org/trac/ghc/ticket/3632#comment:2>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler_______________________________________________
Glasgow-haskell-bugs mailing list
[email protected]
http://www.haskell.org/mailman/listinfo/glasgow-haskell-bugs