packages feed

typelet-0.1.0.0: test/Test/WithoutPlugin.hs

{-# OPTIONS_GHC -ddump-ds-preopt -ddump-ds -ddump-simpl -ddump-to-file #-}

-- | Show that we do not /need/ the plugin; it's just more convenient.
module Test.WithoutPlugin where

import Data.Kind
import Data.Type.Equality

import Test.Infra

data LetT :: a -> Type where
  LetT :: (b :~: a) -> LetT a

-- The NOINLINE pragma is essential, otherwise the inliner just undoes our work
{-# NOINLINE letT #-}
letT :: LetT a
letT = LetT Refl

castSingleLet :: Int -> Int
castSingleLet x =
    case letT of { LetT (p :: b :~: Int) ->
      let x' :: b
          x' = case p of Refl -> x
      in case p of Refl -> x'
    }

-- | Correct version (albeit somewhat clunky)
hlist1 :: HList '[A, B, C]
hlist1 =
   case letT of { LetT (p2 :: r2 :~: (C : '[])) ->
   case letT of { LetT (p1 :: r1 :~: (B : r2 )) ->
   case letT of { LetT (p0 :: r0 :~: (A : r1 )) ->

     let xs2 :: HList r2
         xs1 :: HList r1
         xs0 :: HList r0

         xs2 = case p2 of Refl -> HCons C HNil
         xs1 = case p1 of Refl -> HCons B xs2
         xs0 = case p0 of Refl -> HCons A xs1

     in case p0 of { Refl ->
        case p1 of { Refl ->
        case p2 of { Refl ->
          xs0
        }}}

   }}}

-- | Unpacking the equalities in the wrong order (leading to quadratic code)
hlist2 :: HList '[A, B, C]
hlist2 =
   case letT of { LetT (p2 :: r2 :~: (C : '[])) ->
   case letT of { LetT (p1 :: r1 :~: (B : r2 )) ->
   case letT of { LetT (p0 :: r0 :~: (A : r1 )) ->

     let xs2 :: HList r2
         xs1 :: HList r1
         xs0 :: HList r0

         xs2 = case p2 of Refl -> HCons C HNil
         xs1 = case p1 of Refl -> HCons B xs2
         xs0 = case p0 of Refl -> HCons A xs1

     in case p2 of { Refl ->
        case p1 of { Refl ->
        case p0 of { Refl ->
          xs0
        }}}

   }}}

-- | Just for completeness, a version where /we/ construct equality proofs
hlist3 :: HList '[A, B, C]
hlist3 =
   case letT of { LetT (p2 :: r2 :~: (C : '[])) ->
   case letT of { LetT (p1 :: r1 :~: (B : r2 )) ->
   case letT of { LetT (p0 :: r0 :~: (A : r1 )) ->

     let xs2 :: HList r2
         xs1 :: HList r1
         xs0 :: HList r0

         xs2 = castWith (cong (sym p2)) (HCons C HNil)
         xs1 = castWith (cong (sym p1)) (HCons B xs2)
         xs0 = castWith (cong (sym p0)) (HCons A xs1)

     in castWith (cong (comp p0 (comp p1 p2))) xs0

   }}}

{-------------------------------------------------------------------------------
  Auxiliary
-------------------------------------------------------------------------------}

cong :: (a :~: b) -> f a :~: f b
cong Refl = Refl

comp :: (a :~: x : b) -> b :~: c -> a :~: x : c
comp Refl Refl = Refl