the type equality proof yourself.
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# OPTIONS_GHC -Wall -Wno-redundant-constraints #-}
import Data.Type.Bool
import Data.Type.Equality
import Data.Singletons.Bool
import Unsafe.Coerce (unsafeCoerce)
-- Safe version
proof
:: forall a b. (SBoolI a, SBoolI b, (a || b) ~ 'False)
=> (a :~: 'False, b :~: 'False)
proof = case (sbool :: SBool a, sbool :: SBool b) of
(SFalse, SFalse) -> (Refl, Refl)
-- with unsafeCoerce we don't need the contexts. they can be satisfied for all a, b :: Bool
-- and we don't want runtime SBool dictionaries hanging around (would need to change Expr definition)
proof'
:: forall a b. ((a || b) ~ 'False)
=> (a :~: 'False, b :~: 'False)
proof' = (unsafeCoerce trivialRefl, unsafeCoerce trivialRefl)
data Expr t where
Add :: Expr t -> Expr t' -> Expr (t || t')
Lit :: Int -> Expr 'False
Var :: Expr 'True
eval' :: Expr 'False -> Int
eval' (Lit i) = i
eval' (Add a b) = add a b
where
add :: forall t t'. ((t || t') ~ 'False) => Expr t -> Expr t' -> Int
add x y = case proof' :: (t :~: 'False, t' :~: 'False) of
(Refl, Refl) -> eval' x + eval' y