-
Notifications
You must be signed in to change notification settings - Fork 37
Description
Hi, @jul1u5 and I are trying to manually write a special singleton data type for gradually typed hasktorch.
We'd like a generic singleton datatype, SChecked a, that makes it possible to encode two situations:
ais a singleton type itself and therefore checked by the compiler. For instance,acould beSNatorSBool.ais just a type likeNaturalorBooland therefore unchecked by the compiler.
The nice thing about this is that values of type SChecked a can just be passed around like every other (singleton) value, and one can write programs that work with both forms of inputs, checked or unchecked. This is a huge convenience and makes it possible to gradually introduce stronger types.
We already have had success with specialized singleton types that distinguish between the two cases, see, e.g., https://github.com/hasktorch/hasktorch/blob/7bec8c01e85aa5ebf618f27122e88f50b5c75109/experimental/gradually-typed/src/Torch/GraduallyTyped/Layout.hs#L67, but we would like to have a more generic solution.
We have come up with the following encoding for SChecked a:
type Checked :: Type -> Type -> Type
data Checked a b = Checked a | Unchecked b
type SChecked :: Checked a Type -> Type
data SChecked checked where
SUnchecked :: forall b. b -> SChecked @b ('Unchecked b)
SChecked :: forall k a. Sing a -> SChecked @k ('Checked a)
type instance Sing = SChecked
instance (SingKind a, Demote a ~ a) => SingKind (Checked a Type) where
type Demote (Checked a Type) = Checked a a
fromSing (SUnchecked a) = Unchecked a
fromSing (SChecked a) = Checked (fromSing a)
toSing (Unchecked a) = SomeSing (SUnchecked a)
toSing (Checked a) = withSomeSing a $ SomeSing . SCheckedThis works, but the hidden kind annotation @b is a bit clumsy,
foo :: SChecked ('Checked 4)
foo = SChecked (SNat @4)
bar :: SChecked @Bool ('Unchecked Bool)
bar = SUnchecked TrueWe were wondering if someone has a better idea. Thanks!