[ghc-steering-committee] Unlifted data types
Simon Peyton Jones
simonpj at microsoft.com
Thu Aug 19 11:14:01 UTC 2021
| We use types to communicate the externally-visible behavior of our
| programs: the number of arguments to a function and their types, effects
| incurred in the form of monads, etc. Why should liftedness and the
| implications for evaluation strategies be different?
We use them to *communicate* behaviour, but not to *specify* behaviour. That is done by the definition of the function itself.
I'm keen to hear from other members of the committee.
Maybe I should make a proposal, to seek broader input.
Simon
| -----Original Message-----
| From: Eric Seidel <eric at seidel.io>
| Sent: 18 August 2021 14:33
| To: Simon Peyton Jones <simonpj at microsoft.com>; ghc-steering-
| committee at haskell.org; Sebastian Graf <sgraf1337 at gmail.com>
| Subject: Re: [ghc-steering-committee] Unlifted data types
|
| On Wed, Aug 18, 2021, at 03:32, Simon Peyton Jones wrote:
| > Usually if I look at a type signature for a function and don't really
| > understand it, I can rely on the type checker to ensure that it's only
| > called in well-typed ways. I can also just look at the code for the
| > function, and infer a type that is either the same or more general.
|
| Note that we can still rely on the type checker to ensure that IntU is only
| used in well-typed ways. This is strictly about communicating semantics to
| other programmers (not suggesting that's less important).
|
| > Not so here. I boggled that we can write
| > data IntU a b = IntU Int
| > and not know whether it is lifted or not. That's about *semantics*
| > and runtime behaviour, not mere static acceptance/rejection!
| >
| > I suppose my base principle is:
| > * If GHC can infer a type for a declaration
| > * Then it's ok to omit or ignore the type/kind signature
| >
| > That is, signatures (a) are needed when inference is Too Hard (b)
| > restrict polymorphism. But they should not (c) change semantics.
| >
| > Now I know that because of dark corners of the language, defaulting
| > etc, the signature of a function *can* affect its semantics, but it is
| > rare and very much a dark corner -- it's a wart. But this is right at
| > the heart of what every data declaration means. I don't want to use
| > one small wart to justify a much larger wartier wart.
|
| Type classes (and in particular the monomorphism restriction) are a very
| prominent example of signatures affecting runtime semantics in fundamental
| ways. The monomorphism restriction itself is a wart, but the underlying
| difference between
|
| foo :: Num a => a
|
| and
|
| foo :: Int
|
| in terms of runtime representation and sharing are core to the language.
| And in my opinion, the type signature is *exactly* the right place to
| capture these semantic differences.
|
| We use types to communicate the externally-visible behavior of our
| programs: the number of arguments to a function and their types, effects
| incurred in the form of monads, etc. Why should liftedness and the
| implications for evaluation strategies be different? (In fact, as I've
| suggested before, I think we should go further and expose the strictness of
| function arguments in the type system, but that's a separate discussion.)
|
| ---
|
| On a semi-related note, this prompted me to go back and reread the proposal,
| and I'm not entirely clear on one point. In
|
| ```
| data Foo :: TYPE (BoxedRep Unlifted) where
| MkFoo :: Int -> Foo
| ```
|
| Foo is unlifted and arguments of type Foo will be evaluated strictly, but is
| MkFoo itself strict in its Int argument? The proposal doesn't seem to say,
| and I could see arguments in either direction.
More information about the ghc-steering-committee
mailing list