packages feed

eliminators-0.8: tests/GADTSpec.hs

{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE StandaloneKindSignatures #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}
module GADTSpec where

import Data.Kind
import Data.Singletons.TH
import Data.Singletons.TH.Options

import Internal

import Test.Hspec

main :: IO ()
main = hspec spec

spec :: Spec
spec = pure ()

-----

$(withOptions defaultOptions{genSingKindInsts = False} $
  singletons [d|
    type So :: Bool -> Type
    data So b where
      Oh :: So True
  |])

elimSo :: forall (p :: forall (long_sucker :: Bool). So long_sucker ~> Type)
                 (what :: Bool) (s :: So what).
          Sing s
       -> p @@ Oh
       -> p @@ s
elimSo SOh pOh = pOh

type ElimSo :: forall (p :: forall (long_sucker :: Bool). So long_sucker ~> Type)
            -> forall (what :: Bool).
               forall (s :: So what)
            -> p @@ Oh
            -> p @@ s
type family ElimSo p s pOh where
  forall (p :: forall (long_sucker :: Bool). So long_sucker ~> Type)
         (pOh :: p @@ Oh).
    ElimSo p Oh pOh = pOh

elimPropSo :: forall (p :: Bool ~> Prop) (what :: Bool).
              So what
           -> p @@ True
           -> p @@ what
elimPropSo Oh pOh = pOh

type ElimPropSo :: forall (p :: Bool ~> Prop)
                -> forall (what :: Bool).
                   So what
                -> p @@ True
                -> p @@ what
type family ElimPropSo p s pOh where
  forall (p :: Bool ~> Prop) (pOh :: p @@ True).
    ElimPropSo p Oh pOh = pOh

$(withOptions defaultOptions{genSingKindInsts = False} $
  singletons [d|
    type Flarble :: Type -> Type -> Type
    data Flarble a b where
      MkFlarble1 :: a -> Flarble a b
      -- MkFlarble2 :: a ~ Bool => Flarble a (Maybe b)
      MkFlarble2 :: Flarble Bool (Maybe b)
  |])

elimFlarble :: forall (p :: forall x y. Flarble x y ~> Type)
                      a b (f :: Flarble a b).
               Sing f
            -> (forall a' b' (x :: a'). Sing x -> p @@ (MkFlarble1 x :: Flarble a' b'))
            -> (forall b'. p @@ (MkFlarble2 :: Flarble Bool (Maybe b')))
            -> p @@ f
elimFlarble s@(SMkFlarble1 sx) pMkFlarble1 _ =
  case s of
    (_ :: Sing (MkFlarble1 x :: Flarble a' b')) -> pMkFlarble1 @a' @b' @x sx
elimFlarble s@SMkFlarble2 _ pMkFlarble2 =
  case s of
    (_ :: Sing (MkFlarble2 :: Flarble Bool (Maybe b'))) -> pMkFlarble2 @b'

type ElimFlarble ::
     forall (p :: forall x y. Flarble x y ~> Type)
  -> forall a b.
     forall (f :: Flarble a b)
  -> (forall a' b'. forall (x :: a') -> p @@ (MkFlarble1 x :: Flarble a' b'))
  -> (forall b'. p @@ (MkFlarble2 :: Flarble Bool (Maybe b')))
  -> p @@ f
type family ElimFlarble p f pMkFlarble1 pMkFlarble2 where
  forall (p :: forall x y. Flarble x y ~> Type) a b
         (pMkFlarble1 :: forall a' b'. forall (x :: a') -> p @@ (MkFlarble1 x :: Flarble a' b'))
         (pMkFlarble2 :: forall b'. p @@ (MkFlarble2 :: Flarble Bool (Maybe b'))) x.
    ElimFlarble p (MkFlarble1 x :: Flarble a b) pMkFlarble1 pMkFlarble2 =
      pMkFlarble1 @a @b x
  forall (p :: forall x y. Flarble x y ~> Type)
         (pMkFlarble1 :: forall a' b'. forall (x :: a') -> p @@ (MkFlarble1 x :: Flarble a' b'))
         (pMkFlarble2 :: forall b'. p @@ (MkFlarble2 :: Flarble Bool (Maybe b'))) b'.
    ElimFlarble p (MkFlarble2 :: Flarble Bool (Maybe b')) pMkFlarble1 pMkFlarble2 =
      pMkFlarble2 @b'

elimPropFlarble :: forall (p :: Type ~> Type ~> Prop) a b.
                   Flarble a b
                -> (forall a' b'. a' -> p @@ a' @@ b')
                -> (forall b'. p @@ Bool @@ Maybe b')
                -> p @@ a @@ b
elimPropFlarble f@(MkFlarble1 x) pMkFlarble1 _ =
  case f of
    (_ :: Flarble a' b') -> pMkFlarble1 @a' @b' x
elimPropFlarble f@MkFlarble2 _ pMkFlarble2 =
  case f of
    (_ :: Flarble Bool (Maybe b')) -> pMkFlarble2 @b'

type ElimPropFlarble ::
     forall (p :: Type ~> Type ~> Prop)
  -> forall a b.
     Flarble a b
  -> (forall a' b'. a' ~> p @@ a' @@ b')
  -> (forall b'. p @@ Bool @@ Maybe b')
  -> p @@ a @@ b
type family ElimPropFlarble p f pMkFlarble1 pMkFlarble2 where
  forall (p :: Type ~> Type ~> Prop) a b
         (pMkFlarble1 :: forall a' b'. a' ~> p @@ a' @@ b')
         (pMkFlarble2 :: forall b'. p @@ Bool @@ Maybe b') x.
    ElimPropFlarble p (MkFlarble1 x :: Flarble a b) pMkFlarble1 pMkFlarble2 =
      pMkFlarble1 @a @b @@ x
  forall (p :: Type ~> Type ~> Prop)
         (pMkFlarble1 :: forall a' b'. a' ~> p @@ a' @@ b')
         (pMkFlarble2 :: forall b'. p @@ Bool @@ Maybe b') b'.
    ElimPropFlarble p (MkFlarble2 :: Flarble Bool (Maybe b')) pMkFlarble1 pMkFlarble2 =
      pMkFlarble2 @b'

$(withOptions defaultOptions{genSingKindInsts = False} $
  singletons [d|
    type Obj :: Type
    data Obj where
      MkObj :: o -> Obj
  |])

elimObj :: forall (p :: Obj ~> Type) (o :: Obj).
           Sing o
        -> (forall obj (x :: obj). Sing x -> p @@ MkObj x)
        -> p @@ o
elimObj (SMkObj (sx :: Sing (x :: obj))) pMkObj = pMkObj @obj @x sx

type ElimObj :: forall (p :: Obj ~> Type)
                       (o :: Obj)
             -> (forall obj. forall (x :: obj) -> p @@ MkObj x)
             -> p @@ o
type family ElimObj p o pMkObj where
  forall (p :: Obj ~> Type)
         (pMkObj :: forall obj. forall (x :: obj) -> p @@ MkObj x)
         obj (x :: obj).
    ElimObj p (MkObj (x :: obj)) pMkObj = pMkObj @obj x

elimPropObj :: forall (p :: Prop).
               Obj
            -> (forall obj. obj -> p)
            -> p
elimPropObj (MkObj o) pMkObj = pMkObj o

type ElimPropObj :: forall (p :: Prop) -> Obj -> (forall obj. obj ~> p) -> p
type family ElimPropObj p o pMkObj where
  forall (p :: Prop) (pMkObj :: forall obj. obj ~> p) o.
    ElimPropObj p (MkObj o) pMkObj = pMkObj @@ o