[Haskell-cafe] Constraints as a moveable feast?
Anthony Clayden
anthony_clayden at clear.net.nz
Mon Aug 17 10:50:54 UTC 2020
There's the makings of a cute feature in a very old Haskell Language
report. (With thanks to the 'Partial Type Constructors' 2019 paper for
ferreting this out.)
type Num a => Point a = (a, a)
1990 v1.0 Haskell report. Yes that's a type synonym with a constraint. I'll
give their examples, though they don't really demonstrate the potential:
origin :: Point Integer -- we
get Num a => wanted then discharged for free
origin = (0, 0)
-- although the appearance of zero wants Num a anyway
scale :: (Num a) => a -> Point a -> Point a -- seems wrong to give
explicit Num a
scale w (x,y) = (w*x, w*y) -- the
above sig would be inferred anyway
The feature disappeared without trace in the next year's Language report.
I'm thinking we should be able to write
scale :: a -> Point a -> Point a -- get Num
a for free by:
scale :: a -> (Num a => (a, a)) -> (Num a => (a, a)) --
expand the synonym -- this sig currently illegal
scale :: Num a => a -> (a, a) -> (a, a) -- float the
constraints out to the implicit forall
So this isn't specific to type synonyms: in general allow prefixing
constraints to any sub-term in a type; type inference floats them to the
front of the signature. You can kinda get the effect today (so I don't
think this is entirely whacky), by cunning use of dummies and term-level
combinators:
typePoint :: Num a => (a, a)
typePoint = undefined
scale w xy = const (undefined `asTypeOf` xy `asTypeOf` typePoint) (w
`asTypeOf` fst xy)
-- inferred scale :: Num a => a -> (a,a) -> (a,a)
(Putting a dummy undefined on RHS to show there's nothing up my sleeves,
because the actual expression would unify to the right type anyway.)
You can get maybe cleaner code with PatternSignatures. But it's all
workarounds in terms/expressions. I want to do the Right Thing and get it
accepted as a stand-alone signature.
A couple of caveats:
* Haskell 1990 didn't have MultiParam Type Classes;
* nor existential quant.
So if a nested constraint mentions both an existential tyvar with narrow
scope and a universally quant'd tyvar, can't float out that constraint,
have to reject the sig.
The constraint in `type Num a => Point a = ...` appearing to the left of
the introduced type syn, is also reminiscent of DatatypeContexts, so we
could similarly float out the constraints from those appearing within a
sig(?) And this would be a way to put constraints on newtypes similarly(?)
(Can't put constraints on those currently, because there's not really a
data constructor to bind the class dictionary to. Haskell 1990 didn't have
newtypes.)
Or is there something deeply anti-System FC here?
AntC
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.haskell.org/pipermail/haskell-cafe/attachments/20200817/fc69d121/attachment.html>
More information about the Haskell-Cafe
mailing list