packages feed

eliminators-0.9: tests/PolyRecTypes.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 PolyRecTypes where

import Data.Kind
import Data.Singletons.Base.TH

import Internal

$(singletons [d|
  type WeirdList :: Type -> Type
  data WeirdList a = WeirdNil | WeirdCons a (WeirdList (WeirdList a))
  |])

elimWeirdList :: forall (p :: forall t. WeirdList t ~> Type)
                        a (wl :: WeirdList a).
                 Sing wl
              -> (forall t. p @t @@ WeirdNil)
              -> (forall t (x :: t) (xs :: WeirdList (WeirdList t)).
                         Sing x -> Sing xs -> p @(WeirdList t) @@ xs -> p @t @@ (WeirdCons x xs))
              -> p @a @@ wl
elimWeirdList swl pWeirdNil pWeirdCons = go @a @wl swl
  where
    go :: forall t (wlt :: WeirdList t). Sing wlt -> p @t @@ wlt
    go SWeirdNil = pWeirdNil @t
    go (SWeirdCons (sx :: Sing x) (sxs :: Sing xs)) =
      pWeirdCons @t @x @xs sx sxs (go @(WeirdList t) @xs sxs)

type ElimWeirdList :: forall (p :: forall t. WeirdList t ~> Type)
                   -> forall a.
                      forall (wl :: WeirdList a)
                   -> (forall t. p @t @@ WeirdNil)
                   -> (forall t.
                       forall (x :: t) (xs :: WeirdList (WeirdList t)) ->
                       p @(WeirdList t) @@ xs ~> p @t @@ (WeirdCons x xs))
                   -> p @a @@ wl
type family ElimWeirdList p wl pWeirdNil pWeirdCons where
  forall (p :: forall t. WeirdList t ~> Type)
         (pWeirdNil :: forall t. p @t @@ WeirdNil)
         (pWeirdCons :: forall t. forall (x :: t) (xs :: WeirdList (WeirdList t)) ->
                        p @(WeirdList t) @@ xs ~> p @t @@ (WeirdCons x xs))
         a.
    ElimWeirdList p (WeirdNil @a) pWeirdNil pWeirdCons = pWeirdNil @a
  forall (p :: forall t. WeirdList t ~> Type)
         (pWeirdNil :: forall t. p @t @@ WeirdNil)
         (pWeirdCons :: forall t. forall (x :: t) (xs :: WeirdList (WeirdList t)) ->
                        p @(WeirdList t) @@ xs ~> p @t @@ (WeirdCons x xs))
         a (x :: a) (xs :: WeirdList (WeirdList a)).
    ElimWeirdList p (WeirdCons @a x xs) pWeirdNil pWeirdCons =
      pWeirdCons @a x xs @@ ElimWeirdList p @(WeirdList a) xs pWeirdNil pWeirdCons

elimPropWeirdList :: forall (p :: Prop ~> Prop)
                            (a :: Prop).
                     WeirdList a
                  -> (forall (t :: Prop). p @@ t)
                  -> (forall (t :: Prop).
                             t -> WeirdList (WeirdList t) -> p @@ WeirdList t -> p @@ t)
                  -> p @@ a
elimPropWeirdList wl pWeirdNil pWeirdCons = go @a wl
  where
    go :: forall (t :: Prop). WeirdList t -> p @@ t
    go WeirdNil = pWeirdNil @t
    go (WeirdCons x xs) = pWeirdCons @t x xs (go @(WeirdList t) xs)

type ElimPropWeirdList :: forall (p :: Prop ~> Prop)
                       -> forall (a :: Prop).
                          WeirdList a
                       -> (forall (t :: Prop). p @@ t)
                       -> (forall (t :: Prop).
                                  t ~> WeirdList (WeirdList t) ~> p @@ WeirdList t ~> p @@ t)
                       -> p @@ a
type family ElimPropWeirdList p wl pWeirdNil pWeirdCons where
  forall (p :: Prop ~> Prop)
         (pWeirdNil :: forall (t :: Prop). p @@ t)
         (pWeirdCons :: forall (t :: Prop). t ~> WeirdList (WeirdList t) ~> p @@ WeirdList t ~> p @@ t)
         a.
    ElimPropWeirdList p (WeirdNil @a) pWeirdNil pWeirdCons = pWeirdNil @a
  forall (p :: Prop ~> Prop)
         (pWeirdNil :: forall (t :: Prop). p @@ t)
         (pWeirdCons :: forall (t :: Prop). t ~> WeirdList (WeirdList t) ~> p @@ WeirdList t ~> p @@ t)
         a (x :: a) (xs :: WeirdList (WeirdList a)).
    ElimPropWeirdList p (WeirdCons x xs) pWeirdNil pWeirdCons =
      pWeirdCons @a @@ x @@ xs @@ ElimPropWeirdList p @(WeirdList a) xs pWeirdNil pWeirdCons