Unlifted data types

Dan Doel dan.doel at gmail.com
Sat Sep 5 01:21:29 UTC 2015


Here are some additional thoughts.

If we examine an analogue of some of your examples:

    data MutVar a = MV (MutVar# RealWorld a)

    main = do
      let mv# = undefined
      let mv = MV mv#
      putStrLn "Okay."

The above is illegal. Instead we _must_ write:

      let !mv# = undefined

which signals that evaluation is occurring. So it is impossible to
accidentally go from:

    main = do
      let mv = MV undefined
      putStrLn "Okay."

which prints "Okay.", to something that throws an exception, without
having a pretty good indication that you're doing so. I would guess
this is desirable, so perhaps it should be mandated for Unlifted as
well.

----

However, the above point confuses me with respect to another example.
The proposal says that:

    data Id :: * -> Unlifted where
      Id :: a -> Id a

could/should be compiled with no overhead over `a`, like a newtype.
However, if Unlifted things have operational semantics like #, what
does the following do:

    let x :: Id a
        !x = Id undefined

The ! should evaluate to the Id constructor, but we're not
representing it, so it actually doesn't evaluate anything? But:

    let x :: Id a
        !x = undefined

throws an exception? Whereas for newtypes, both throw exceptions with
a !x definition, or don't with an x definition? Is it actually
possible to make Id behave this way without any representational
overhead?

I'm a little skeptical. I think that only Force (and Box) might be
able to have no representational overhead.

-- Dan


On Fri, Sep 4, 2015 at 5:23 PM, Edward Z. Yang <ezyang at mit.edu> wrote:
> Excerpts from Dan Doel's message of 2015-09-04 13:09:26 -0700:
>> Okay. That answers another question I had, which was whether MutVar#
>> and such would go in the new kind.
>>
>> So now we have partial, extended natural numbers:
>>
>>     data PNat :: * where
>>       PZero :: PNat
>>       PSuc :: PNat -> PNat
>>
>> A flat domain of natural numbers:
>>
>>     data FNat :: * where
>>       FZero :: FNat
>>       FSuc :: !FNat -> FNat
>>
>> And two sets of natural numbers:
>>
>>     Force FNat :: Unlifted
>>
>>     data UNat :: Unlifted where
>>       UZero :: UNat
>>       USuc :: UNat -> UNat
>>
>> And really perhaps two flat domains (and three sets), if you use Force
>> instead of !, which would differ on who ensures the evaluation. That's
>> kind of a lot of incompatible definitions of essentially the same
>> thing (PNat being the significantly different thing).
>>
>> I was kind of more enthused about first class !a. For instance, if you
>> think about the opening quote by Bob Harper, he's basically wrong. The
>> flat domain FNat is the natural numbers (existing in an overall lazy
>> language), and has the reasoning properties he wants to teach students
>> about with very little complication. It'd be satisfying to recognize
>> that unlifting the outer-most part gets you exactly there, with
>> whatever performance characteristics that implies. Or to get rid of !
>> and use Unlifted definitions instead.
>>
>> Maybe backwards compatibility mandates the duplication, but it'd be
>> nice if some synthesis could be reached.
>
> I would certainly agree that in terms of the data that is representable,
> there is not much difference; but there is a lot of difference for the
> client between Force and a strict field. If I write:
>
>     let x = undefined
>         y = Strict x
>     in True
>
> No error occurs with:
>
>     data Strict = Strict !a
>
> But an error occurs with:
>
>     data Strict = Strict (Force a)
>
> One possibility for how to reconcile the difference for BC is to posit
> that there are just two different constructors:
>
>     Strict  ::       a -> Strict a
>     Strict! :: Force a -> Strict a
>
> But this kind of special handling is a bit bothersome. Consider:
>
>     data SPair a b = SPair (!a, !b)
>
> The constructor has what type?  Probably
>
>     SPair :: (Force a, Force b) -> SPair a
>
> and not:
>
>     SPair :: (a, b) -> SPair a
>
>> It'd also be good to think about/specify how this is going to interact
>> with unpacked/unboxed sums.
>
> I don't think it interacts any differently than with unpacked/unboxed
> products today.
>
> Edward


More information about the ghc-devs mailing list