eliminators 0.2 → 0.3
raw patch · 12 files changed
+615/−266 lines, 12 filesdep +singleton-natsPVP ok
version bump matches the API change (PVP)
Dependencies added: singleton-nats
API changes (from Hackage documentation)
+ Data.Eliminator.TypeNats: elimNat :: forall (p :: Nat ~> Type) (n :: Nat). Sing n -> p @@ 0 -> (forall (k :: Nat). Sing k -> p @@ k -> p @@ (k + 1)) -> p @@ n
- Data.Eliminator: elimBool :: forall (p_api4 :: (~>) Bool Type) (s_api5 :: Bool). Sing s_api5 -> (@@) p_api4 False -> (@@) p_api4 True -> (@@) p_api4 s_api5
+ Data.Eliminator: elimBool :: forall (p_aqvV :: (~>) Bool Type) (s_aqvW :: Bool). Sing s_aqvW -> (@@) p_aqvV False -> (@@) p_aqvV True -> (@@) p_aqvV s_aqvW
- Data.Eliminator: elimEither :: forall (a_ao1l :: Type) (b_ao1m :: Type) (p_apia :: (~>) (Either a_ao1l b_ao1m) Type) (s_apib :: Either a_ao1l b_ao1m). Sing s_apib -> (forall (f0_apic :: a_ao1l). Sing f0_apic -> (@@) p_apia (Left f0_apic)) -> (forall (f0_apid :: b_ao1m). Sing f0_apid -> (@@) p_apia (Right f0_apid)) -> (@@) p_apia s_apib
+ Data.Eliminator: elimEither :: forall (a_apE1 :: Type) (b_apE2 :: Type) (p_aqw1 :: (~>) (Either a_apE1 b_apE2) Type) (s_aqw2 :: Either a_apE1 b_apE2). Sing s_aqw2 -> (forall (f0_aqw3 :: a_apE1). Sing f0_aqw3 -> (@@) p_aqw1 (Left f0_aqw3)) -> (forall (f0_aqw4 :: b_apE2). Sing f0_aqw4 -> (@@) p_aqw1 (Right f0_aqw4)) -> (@@) p_aqw1 s_aqw2
- Data.Eliminator: elimList :: forall (a_11 :: Type) (p_apGd :: (~>) ([] a_11) Type) (s_apGe :: [] a_11). Sing s_apGe -> (@@) p_apGd [] -> (forall (f0_apGf :: a_11). Sing f0_apGf -> forall (f1_apGg :: [a_11]). Sing f1_apGg -> (@@) p_apGd f1_apGg -> (@@) p_apGd ((:) f0_apGf f1_apGg)) -> (@@) p_apGd s_apGe
+ Data.Eliminator: elimList :: forall (a_11 :: Type) (p_aqWq :: (~>) ([] a_11) Type) (s_aqWr :: [] a_11). Sing s_aqWr -> (@@) p_aqWq [] -> (forall (f0_aqWs :: a_11). Sing f0_aqWs -> forall (f1_aqWt :: [a_11]). Sing f1_aqWt -> (@@) p_aqWq f1_aqWt -> (@@) p_aqWq ((:) f0_aqWs f1_aqWt)) -> (@@) p_aqWq s_aqWr
- Data.Eliminator: elimMaybe :: forall (a_11 :: Type) (p_apim :: (~>) (Maybe a_11) Type) (s_apin :: Maybe a_11). Sing s_apin -> (@@) p_apim Nothing -> (forall (f0_apio :: a_11). Sing f0_apio -> (@@) p_apim (Just f0_apio)) -> (@@) p_apim s_apin
+ Data.Eliminator: elimMaybe :: forall (a_11 :: Type) (p_aqwd :: (~>) (Maybe a_11) Type) (s_aqwe :: Maybe a_11). Sing s_aqwe -> (@@) p_aqwd Nothing -> (forall (f0_aqwf :: a_11). Sing f0_aqwf -> (@@) p_aqwd (Just f0_aqwf)) -> (@@) p_aqwd s_aqwe
- Data.Eliminator: elimNat :: forall (p :: Nat ~> Type) (n :: Nat). Sing n -> p @@ 0 -> (forall (k :: Nat). Sing k -> p @@ k -> p @@ (k + 1)) -> p @@ n
+ Data.Eliminator: elimNat :: forall (p_aqwm :: (~>) Nat Type) (s_aqwn :: Nat). Sing s_aqwn -> (@@) p_aqwm Z -> (forall (f0_aqwo :: Nat). Sing f0_aqwo -> (@@) p_aqwm f0_aqwo -> (@@) p_aqwm (S f0_aqwo)) -> (@@) p_aqwm s_aqwn
- Data.Eliminator: elimNonEmpty :: forall (a_ajh8 :: Type) (p_apiv :: (~>) (NonEmpty a_ajh8) Type) (s_apiw :: NonEmpty a_ajh8). Sing s_apiw -> (forall (f0_apix :: a_ajh8). Sing f0_apix -> forall (f1_apiy :: [a_ajh8]). Sing f1_apiy -> (@@) p_apiv ((:|) f0_apix f1_apiy)) -> (@@) p_apiv s_apiw
+ Data.Eliminator: elimNonEmpty :: forall (a_akqR :: Type) (p_aqwv :: (~>) (NonEmpty a_akqR) Type) (s_aqww :: NonEmpty a_akqR). Sing s_aqww -> (forall (f0_aqwx :: a_akqR). Sing f0_aqwx -> forall (f1_aqwy :: [a_akqR]). Sing f1_aqwy -> (@@) p_aqwv ((:|) f0_aqwx f1_aqwy)) -> (@@) p_aqwv s_aqww
- Data.Eliminator: elimOrdering :: forall (p_apiE :: (~>) Ordering Type) (s_apiF :: Ordering). Sing s_apiF -> (@@) p_apiE LT -> (@@) p_apiE EQ -> (@@) p_apiE GT -> (@@) p_apiE s_apiF
+ Data.Eliminator: elimOrdering :: forall (p_aqwE :: (~>) Ordering Type) (s_aqwF :: Ordering). Sing s_aqwF -> (@@) p_aqwE LT -> (@@) p_aqwE EQ -> (@@) p_aqwE GT -> (@@) p_aqwE s_aqwF
- Data.Eliminator: elimTuple0 :: forall (p_apN7 :: (~>) () Type) (s_apN8 :: ()). Sing s_apN8 -> (@@) p_apN7 () -> (@@) p_apN7 s_apN8
+ Data.Eliminator: elimTuple0 :: forall (p_ar3E :: (~>) () Type) (s_ar3F :: ()). Sing s_ar3F -> (@@) p_ar3E () -> (@@) p_ar3E s_ar3F
- Data.Eliminator: elimTuple2 :: forall (a_11 :: Type) (b_12 :: Type) (p_apNa :: (~>) ((,) a_11 b_12) Type) (s_apNb :: (,) a_11 b_12). Sing s_apNb -> (forall (f0_apNc :: a_11). Sing f0_apNc -> forall (f1_apNd :: b_12). Sing f1_apNd -> (@@) p_apNa ((,) f0_apNc f1_apNd)) -> (@@) p_apNa s_apNb
+ Data.Eliminator: elimTuple2 :: forall (a_11 :: Type) (b_12 :: Type) (p_ar3H :: (~>) ((,) a_11 b_12) Type) (s_ar3I :: (,) a_11 b_12). Sing s_ar3I -> (forall (f0_ar3J :: a_11). Sing f0_ar3J -> forall (f1_ar3K :: b_12). Sing f1_ar3K -> (@@) p_ar3H ((,) f0_ar3J f1_ar3K)) -> (@@) p_ar3H s_ar3I
- Data.Eliminator: elimTuple3 :: forall (a_11 :: Type) (b_12 :: Type) (c_13 :: Type) (p_apNj :: (~>) ((,,) a_11 b_12 c_13) Type) (s_apNk :: (,,) a_11 b_12 c_13). Sing s_apNk -> (forall (f0_apNl :: a_11). Sing f0_apNl -> forall (f1_apNm :: b_12). Sing f1_apNm -> forall (f2_apNn :: c_13). Sing f2_apNn -> (@@) p_apNj ((,,) f0_apNl f1_apNm f2_apNn)) -> (@@) p_apNj s_apNk
+ Data.Eliminator: elimTuple3 :: forall (a_11 :: Type) (b_12 :: Type) (c_13 :: Type) (p_ar3Q :: (~>) ((,,) a_11 b_12 c_13) Type) (s_ar3R :: (,,) a_11 b_12 c_13). Sing s_ar3R -> (forall (f0_ar3S :: a_11). Sing f0_ar3S -> forall (f1_ar3T :: b_12). Sing f1_ar3T -> forall (f2_ar3U :: c_13). Sing f2_ar3U -> (@@) p_ar3Q ((,,) f0_ar3S f1_ar3T f2_ar3U)) -> (@@) p_ar3Q s_ar3R
- Data.Eliminator: elimTuple4 :: forall (a_11 :: Type) (b_12 :: Type) (c_13 :: Type) (d_14 :: Type) (p_apNv :: (~>) ((,,,) a_11 b_12 c_13 d_14) Type) (s_apNw :: (,,,) a_11 b_12 c_13 d_14). Sing s_apNw -> (forall (f0_apNx :: a_11). Sing f0_apNx -> forall (f1_apNy :: b_12). Sing f1_apNy -> forall (f2_apNz :: c_13). Sing f2_apNz -> forall (f3_apNA :: d_14). Sing f3_apNA -> (@@) p_apNv ((,,,) f0_apNx f1_apNy f2_apNz f3_apNA)) -> (@@) p_apNv s_apNw
+ Data.Eliminator: elimTuple4 :: forall (a_11 :: Type) (b_12 :: Type) (c_13 :: Type) (d_14 :: Type) (p_ar42 :: (~>) ((,,,) a_11 b_12 c_13 d_14) Type) (s_ar43 :: (,,,) a_11 b_12 c_13 d_14). Sing s_ar43 -> (forall (f0_ar44 :: a_11). Sing f0_ar44 -> forall (f1_ar45 :: b_12). Sing f1_ar45 -> forall (f2_ar46 :: c_13). Sing f2_ar46 -> forall (f3_ar47 :: d_14). Sing f3_ar47 -> (@@) p_ar42 ((,,,) f0_ar44 f1_ar45 f2_ar46 f3_ar47)) -> (@@) p_ar42 s_ar43
- Data.Eliminator: elimTuple5 :: forall (a_11 :: Type) (b_12 :: Type) (c_13 :: Type) (d_14 :: Type) (e_15 :: Type) (p_apNK :: (~>) ((,,,,) a_11 b_12 c_13 d_14 e_15) Type) (s_apNL :: (,,,,) a_11 b_12 c_13 d_14 e_15). Sing s_apNL -> (forall (f0_apNM :: a_11). Sing f0_apNM -> forall (f1_apNN :: b_12). Sing f1_apNN -> forall (f2_apNO :: c_13). Sing f2_apNO -> forall (f3_apNP :: d_14). Sing f3_apNP -> forall (f4_apNQ :: e_15). Sing f4_apNQ -> (@@) p_apNK ((,,,,) f0_apNM f1_apNN f2_apNO f3_apNP f4_apNQ)) -> (@@) p_apNK s_apNL
+ Data.Eliminator: elimTuple5 :: forall (a_11 :: Type) (b_12 :: Type) (c_13 :: Type) (d_14 :: Type) (e_15 :: Type) (p_ar4h :: (~>) ((,,,,) a_11 b_12 c_13 d_14 e_15) Type) (s_ar4i :: (,,,,) a_11 b_12 c_13 d_14 e_15). Sing s_ar4i -> (forall (f0_ar4j :: a_11). Sing f0_ar4j -> forall (f1_ar4k :: b_12). Sing f1_ar4k -> forall (f2_ar4l :: c_13). Sing f2_ar4l -> forall (f3_ar4m :: d_14). Sing f3_ar4m -> forall (f4_ar4n :: e_15). Sing f4_ar4n -> (@@) p_ar4h ((,,,,) f0_ar4j f1_ar4k f2_ar4l f3_ar4m f4_ar4n)) -> (@@) p_ar4h s_ar4i
- Data.Eliminator: elimTuple6 :: forall (a_11 :: Type) (b_12 :: Type) (c_13 :: Type) (d_14 :: Type) (e_15 :: Type) (f_16 :: Type) (p_apO2 :: (~>) ((,,,,,) a_11 b_12 c_13 d_14 e_15 f_16) Type) (s_apO3 :: (,,,,,) a_11 b_12 c_13 d_14 e_15 f_16). Sing s_apO3 -> (forall (f0_apO4 :: a_11). Sing f0_apO4 -> forall (f1_apO5 :: b_12). Sing f1_apO5 -> forall (f2_apO6 :: c_13). Sing f2_apO6 -> forall (f3_apO7 :: d_14). Sing f3_apO7 -> forall (f4_apO8 :: e_15). Sing f4_apO8 -> forall (f5_apO9 :: f_16). Sing f5_apO9 -> (@@) p_apO2 ((,,,,,) f0_apO4 f1_apO5 f2_apO6 f3_apO7 f4_apO8 f5_apO9)) -> (@@) p_apO2 s_apO3
+ Data.Eliminator: elimTuple6 :: forall (a_11 :: Type) (b_12 :: Type) (c_13 :: Type) (d_14 :: Type) (e_15 :: Type) (f_16 :: Type) (p_ar4z :: (~>) ((,,,,,) a_11 b_12 c_13 d_14 e_15 f_16) Type) (s_ar4A :: (,,,,,) a_11 b_12 c_13 d_14 e_15 f_16). Sing s_ar4A -> (forall (f0_ar4B :: a_11). Sing f0_ar4B -> forall (f1_ar4C :: b_12). Sing f1_ar4C -> forall (f2_ar4D :: c_13). Sing f2_ar4D -> forall (f3_ar4E :: d_14). Sing f3_ar4E -> forall (f4_ar4F :: e_15). Sing f4_ar4F -> forall (f5_ar4G :: f_16). Sing f5_ar4G -> (@@) p_ar4z ((,,,,,) f0_ar4B f1_ar4C f2_ar4D f3_ar4E f4_ar4F f5_ar4G)) -> (@@) p_ar4z s_ar4A
- Data.Eliminator: elimTuple7 :: forall (a_11 :: Type) (b_12 :: Type) (c_13 :: Type) (d_14 :: Type) (e_15 :: Type) (f_16 :: Type) (g_17 :: Type) (p_apOn :: (~>) ((,,,,,,) a_11 b_12 c_13 d_14 e_15 f_16 g_17) Type) (s_apOo :: (,,,,,,) a_11 b_12 c_13 d_14 e_15 f_16 g_17). Sing s_apOo -> (forall (f0_apOp :: a_11). Sing f0_apOp -> forall (f1_apOq :: b_12). Sing f1_apOq -> forall (f2_apOr :: c_13). Sing f2_apOr -> forall (f3_apOs :: d_14). Sing f3_apOs -> forall (f4_apOt :: e_15). Sing f4_apOt -> forall (f5_apOu :: f_16). Sing f5_apOu -> forall (f6_apOv :: g_17). Sing f6_apOv -> (@@) p_apOn ((,,,,,,) f0_apOp f1_apOq f2_apOr f3_apOs f4_apOt f5_apOu f6_apOv)) -> (@@) p_apOn s_apOo
+ Data.Eliminator: elimTuple7 :: forall (a_11 :: Type) (b_12 :: Type) (c_13 :: Type) (d_14 :: Type) (e_15 :: Type) (f_16 :: Type) (g_17 :: Type) (p_ar4U :: (~>) ((,,,,,,) a_11 b_12 c_13 d_14 e_15 f_16 g_17) Type) (s_ar4V :: (,,,,,,) a_11 b_12 c_13 d_14 e_15 f_16 g_17). Sing s_ar4V -> (forall (f0_ar4W :: a_11). Sing f0_ar4W -> forall (f1_ar4X :: b_12). Sing f1_ar4X -> forall (f2_ar4Y :: c_13). Sing f2_ar4Y -> forall (f3_ar4Z :: d_14). Sing f3_ar4Z -> forall (f4_ar50 :: e_15). Sing f4_ar50 -> forall (f5_ar51 :: f_16). Sing f5_ar51 -> forall (f6_ar52 :: g_17). Sing f6_ar52 -> (@@) p_ar4U ((,,,,,,) f0_ar4W f1_ar4X f2_ar4Y f3_ar4Z f4_ar50 f5_ar51 f6_ar52)) -> (@@) p_ar4U s_ar4V
Files
- CHANGELOG.md +7/−0
- eliminators.cabal +17/−13
- src/Data/Eliminator.hs +8/−28
- src/Data/Eliminator/TH.hs +1/−1
- src/Data/Eliminator/TypeNats.hs +39/−0
- tests/DecideSpec.hs +222/−0
- tests/DecideTypes.hs +106/−0
- tests/EqualitySpec.hs +30/−8
- tests/PeanoSpec.hs +0/−117
- tests/PeanoTypes.hs +0/−94
- tests/VecSpec.hs +105/−5
- tests/VecTypes.hs +80/−0
CHANGELOG.md view
@@ -1,3 +1,10 @@+## 0.3 [2017-11-07]+* Migrate the old `elimNat` from `Data.Eliminator` (which worked over the `Nat`+ from `GHC.TypeNats`) to `Data.Eliminator.TypeNats`. There `elimNat` that now+ lives in `Data.Eliminator` is for an unrelated `Nat` data type from the+ `singleton-nats` package (which is a proper, inductively defined, Peano+ natural number type).+ ## 0.2 [2017-07-22] * Introduce the `Data.Eliminator.TH` module, which provides functionality for generating eliminator functions using Template Haskell. Currently, only
eliminators.cabal view
@@ -1,5 +1,5 @@ name: eliminators-version: 0.2+version: 0.3 synopsis: Dependently typed elimination functions using singletons description: This library provides eliminators for inductive data types, leveraging the power of the @singletons@ library to allow@@ -25,12 +25,14 @@ library exposed-modules: Data.Eliminator Data.Eliminator.TH- build-depends: base >= 4.10 && < 4.11- , extra >= 1.4.2 && < 1.7- , singletons >= 2.3 && < 2.4- , template-haskell >= 2.12 && < 2.13- , th-abstraction >= 0.2.3 && < 0.3- , th-desugar >= 1.7 && < 1.8+ Data.Eliminator.TypeNats+ build-depends: base >= 4.10 && < 4.11+ , extra >= 1.4.2 && < 1.7+ , singletons >= 2.3 && < 2.4+ , singleton-nats >= 0.4.0.3 && < 0.5+ , template-haskell >= 2.12 && < 2.13+ , th-abstraction >= 0.2.3 && < 0.3+ , th-desugar >= 1.7 && < 1.8 hs-source-dirs: src default-language: Haskell2010 ghc-options: -Wall -Wno-unticked-promoted-constructors@@ -38,17 +40,19 @@ test-suite spec type: exitcode-stdio-1.0 main-is: Spec.hs- other-modules: EqualitySpec+ other-modules: DecideSpec+ DecideTypes+ EqualitySpec GADTSpec ListSpec ListTypes- PeanoSpec- PeanoTypes+ VecTypes VecSpec- build-depends: base >= 4.10 && < 4.11+ build-depends: base >= 4.10 && < 4.11 , eliminators- , hspec >= 2 && < 3- , singletons >= 2.3 && < 2.4+ , hspec >= 2 && < 3+ , singletons >= 2.3 && < 2.4+ , singleton-nats >= 0.4.0.3 && < 0.5 hs-source-dirs: tests default-language: Haskell2010 ghc-options: -Wall -Wno-unticked-promoted-constructors -threaded -rtsopts
src/Data/Eliminator.hs view
@@ -39,20 +39,15 @@ , elimTuple7 ) where -import Control.Monad.Extra--import Data.Eliminator.TH-import Data.Kind (Type)-import Data.List.NonEmpty (NonEmpty(..))-import Data.Singletons.Prelude-import Data.Singletons.Prelude.List.NonEmpty (Sing(..))-import Data.Singletons.TypeLits--import qualified GHC.TypeLits as TL+import Control.Monad.Extra -import Language.Haskell.TH.Desugar (tupleNameDegree_maybe)+import Data.Eliminator.TH+import Data.List.NonEmpty (NonEmpty(..))+import Data.Nat+import Data.Singletons.Prelude+import Data.Singletons.Prelude.List.NonEmpty (Sing(..)) -import Unsafe.Coerce (unsafeCoerce)+import Language.Haskell.TH.Desugar (tupleNameDegree_maybe) {- $eliminators @@ -70,23 +65,8 @@ with @~>@ prepended. -} -$(concatMapM deriveElim [''Bool, ''Either, ''Maybe, ''NonEmpty, ''Ordering])+$(concatMapM deriveElim [''Bool, ''Either, ''Maybe, ''Nat, ''NonEmpty, ''Ordering]) $(deriveElimNamed "elimList" ''[]) $(concatMapM (\n -> let Just deg = tupleNameDegree_maybe n in deriveElimNamed ("elimTuple" ++ show deg) n) [''(), ''(,), ''(,,), ''(,,,), ''(,,,,), ''(,,,,,), ''(,,,,,,)])---- This is the grimy one we can't define using Template Haskell.---- | Although 'Nat' is not actually an inductive data type in GHC, we can--- pretend that it is using this eliminator.-elimNat :: forall (p :: Nat ~> Type) (n :: Nat).- Sing n- -> p @@ 0- -> (forall (k :: Nat). Sing k -> p @@ k -> p @@ (k TL.+ 1))- -> p @@ n-elimNat snat pZ pS =- case fromSing snat of- 0 -> unsafeCoerce pZ- nPlusOne -> withSomeSing (pred nPlusOne) $ \(sn :: Sing k) ->- unsafeCoerce (pS sn (elimNat @p @k sn pZ pS))
src/Data/Eliminator/TH.hs view
@@ -53,7 +53,7 @@ -> p '@@' l elimMyList SMyNil pMyNil _ = pMyNil elimMyList (SMyCons (x' :: 'Sing' x) (xs' :: 'Sing' xs)) pMyNil pMyCons- = pMyCons x' xs' (elimMyList @a @p @xs pMyNil pMyCons)+ = pMyCons x' xs' (elimMyList \@a \@p \@xs pMyNil pMyCons) @ There are some important things to note here:
+ src/Data/Eliminator/TypeNats.hs view
@@ -0,0 +1,39 @@+{-# LANGUAGE AllowAmbiguousTypes #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE Trustworthy #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE TypeInType #-}+{-# LANGUAGE TypeOperators #-}+{-|+Module: Data.Eliminator.TypeNats+Copyright: (C) 2017 Ryan Scott+License: BSD-style (see the file LICENSE)+Maintainer: Ryan Scott+Stability: Experimental+Portability: GHC++A crude imitation of an eliminator function for 'GHC.TypeNats.Nat'.+-}+module Data.Eliminator.TypeNats (elimNat) where++import Data.Kind (Type)+import Data.Singletons+import Data.Singletons.TypeLits++import GHC.TypeNats++import Unsafe.Coerce (unsafeCoerce)++-- | Although 'Nat' is not actually an inductive data type in GHC, we can+-- (crudely) pretend that it is using this eliminator.+elimNat :: forall (p :: Nat ~> Type) (n :: Nat).+ Sing n+ -> p @@ 0+ -> (forall (k :: Nat). Sing k -> p @@ k -> p @@ (k + 1))+ -> p @@ n+elimNat snat pZ pS =+ case fromSing snat of+ 0 -> unsafeCoerce pZ+ nPlusOne -> withSomeSing (pred nPlusOne) $ \(sn :: Sing k) ->+ unsafeCoerce (pS sn (elimNat @p @k sn pZ pS))
+ tests/DecideSpec.hs view
@@ -0,0 +1,222 @@+{-# LANGUAGE GADTs #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeInType #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE UndecidableInstances #-}+module DecideSpec where++import Data.Eliminator+import Data.Nat+import Data.Singletons.Prelude+import Data.Singletons.TH hiding (Decision(..))+import Data.Type.Equality++import EqualitySpec (cong, replace)+import DecideTypes++import Test.Hspec++main :: IO ()+main = hspec spec++spec :: Spec+spec = parallel $ do+ let proved = "Proved Refl"+ disproved = "Disproved <void>"+ describe "decEqNat" $ do+ it "returns evidence that two Nats are equal" $ do+ show (decEqNat (sLit @0) (sLit @0)) `shouldBe` proved+ show (decEqNat (sLit @1) (sLit @0)) `shouldBe` disproved+ show (decEqNat (sLit @0) (sLit @1)) `shouldBe` disproved+ show (decEqNat (sLit @1) (sLit @1)) `shouldBe` proved+ describe "decEqList" $ do+ it "returns evidence that two lists are equal" $ do+ let decEqNatList = decEqList decEqNat+ show (decEqNatList SNil SNil) `shouldBe` proved+ show (decEqNatList (SCons (sLit @0) SNil) SNil) `shouldBe` disproved+ show (decEqNatList SNil (SCons (sLit @0) SNil)) `shouldBe` disproved+ show (decEqNatList (SCons (sLit @0) SNil) (SCons (sLit @0) SNil)) `shouldBe` proved+ -- TODO: Try this in the next version of singletons+ -- show (decEqNatList (SCons (sLit @1) SNil) (SCons (sLit @0) SNil)) `shouldBe` disproved++-----++peanoEqConsequencesSame :: forall (n :: Nat). Sing n -> NatEqConsequences n n+peanoEqConsequencesSame sn = elimNat @WhyNatEqConsequencesSameSym0 @n sn base step+ where+ base :: WhyNatEqConsequencesSame Z+ base = ()++ step :: forall (k :: Nat).+ Sing k+ -> WhyNatEqConsequencesSame k+ -> WhyNatEqConsequencesSame (S k)+ step _ _ = Refl++useNatEq :: forall n j. Sing n -> n :~: j -> NatEqConsequences n j+useNatEq sn nEqJ = replace @Nat @n @j @(NatEqConsequencesSym1 n)+ (peanoEqConsequencesSame @n sn) nEqJ++zNotS :: forall n. Z :~: S n -> Void+zNotS = useNatEq @Z @(S n) SZ++sNotZ :: forall n. S n :~: Z -> Void+sNotZ eq = zNotS @n (sym eq)++sInjective :: forall n j. Sing n -> S n :~: S j -> n :~: j+sInjective sn = useNatEq @(S n) @(S j) (SS sn)++decEqZ :: forall (j :: Nat). Sing j -> Decision (Z :~: j)+decEqZ sj = elimNat @WhyDecEqZSym0 @j sj base step+ where+ base :: Decision (Z :~: Z)+ base = Proved Refl++ step :: forall (k :: Nat).+ Sing k -> Decision (Z :~: k) -> Decision (Z :~: S k)+ step _ _ = Disproved (zNotS @k)++decCongS :: forall n j. Sing n -> Decision (n :~: j) -> Decision (S n :~: S j)+decCongS sn dNJ = withSomeSing dNJ $ \(sDNJ :: Sing d) ->+ elimDecision @_ @(ConstSym1 (Decision (S n :~: S j))) @d+ sDNJ left right+ where+ left :: forall (x :: n :~: j).+ Sing x -> Decision (S n :~: S j)+ left yes = Proved $ cong @Nat @Nat @(TyCon1 S) @n @j (fromSing yes)++ right :: forall (r :: (n :~: j) ~> Void).+ Sing r -> Decision (S n :~: S j)+ right no = Disproved $ fromSing no . sInjective @n @j sn++decEqNat :: forall (n :: Nat) (j :: Nat). Sing n -> Sing j -> Decision (n :~: j)+decEqNat sn = runWhyDecEqNat (elimNat @(TyCon1 WhyDecEqNat) @n sn base step)+ where+ base :: WhyDecEqNat Z+ base = WhyDecEqNat decEqZ++ step :: forall (k :: Nat).+ Sing k+ -> WhyDecEqNat k+ -> WhyDecEqNat (S k)+ step sk swhyK = WhyDecEqNat $ \(sl :: Sing l) ->+ elimNat @(WhyDecEqSSym1 k) @l sl baseStep stepStep+ where+ baseStep :: Decision (S k :~: Z)+ baseStep = Disproved $ sNotZ @k++ stepStep :: forall (m :: Nat).+ Sing m+ -> Decision (S k :~: m)+ -> Decision (S k :~: S m)+ stepStep sm _ = decCongS sk (runWhyDecEqNat swhyK sm)++listEqConsequencesSame :: forall (es :: [e]). Sing es -> ListEqConsequences es es+listEqConsequencesSame sl = elimList @e @WhyListEqConsequencesSameSym0 @es sl base step+ where+ base :: ListEqConsequences '[] '[]+ base = ()++ step :: forall (x :: e) (xs :: [e]).+ Sing x -> Sing xs+ -> ListEqConsequences xs xs+ -> ListEqConsequences (x:xs) (x:xs)+ step _ _ _ = (Refl, Refl)++useListEq :: forall (xs :: [e]) (ys :: [e]).+ Sing xs -> xs :~: ys -> ListEqConsequences xs ys+useListEq sxs xsEqYs = replace @[e] @xs @ys @(ListEqConsequencesSym1 xs)+ (listEqConsequencesSame @e @xs sxs) xsEqYs++nilNotCons :: forall (x :: e) (xs :: [e]). '[] :~: (x:xs) -> Void+nilNotCons = useListEq @e @'[] @(x:xs) SNil++consNotNil :: forall (x :: e) (xs :: [e]). (x:xs) :~: '[] -> Void+consNotNil eq = nilNotCons @e @x @xs (sym eq)++consInjective :: forall (x :: e) (xs :: [e]) (y :: e) (ys :: [e]).+ Sing x -> Sing xs+ -> (x:xs) :~: (y:ys)+ -> (x :~: y, xs :~: ys)+consInjective sx sxs = useListEq @e @(x:xs) @(y:ys) (SCons sx sxs)++decEqNil :: forall (es :: [e]). Sing es -> Decision ('[] :~: es)+decEqNil ses = elimList @e @WhyDecEqNilSym0 @es ses base step+ where+ base :: Decision ('[] :~: '[])+ base = Proved Refl++ step :: forall (x :: e) (xs :: [e]).+ Sing x -> Sing xs+ -> Decision ('[] :~: xs)+ -> Decision ('[] :~: (x:xs))+ step _ _ _ = Disproved (nilNotCons @e @x @xs)++intermixListEqs :: forall (x :: e) (xs :: [e]) (y :: e) (ys :: [e]).+ x :~: y -> xs :~: ys+ -> (x:xs) :~: (y:ys)+intermixListEqs xEqY xsEqYs =+ replace @e @x @y @(WhyIntermixListEqs1Sym3 x xs ys)+ (replace @[e] @xs @ys @(WhyIntermixListEqs2Sym2 x xs) Refl xsEqYs)+ xEqY++decCongCons :: forall (x :: e) (xs :: [e]) (y :: e) (ys :: [e]).+ Sing x -> Sing xs+ -> Decision (x :~: y) -> Decision (xs :~: ys)+ -> Decision ((x:xs) :~: (y:ys))+decCongCons sx sxs dXY dXsYs =+ withSomeSing dXY $ \(sDXY :: Sing dXY) ->+ elimDecision @_ @(ConstSym1 (Decision ((x:xs) :~: (y:ys)))) @dXY+ sDXY left right+ where+ left :: forall (z :: x :~: y).+ Sing z -> Decision ((x:xs) :~: (y:ys))+ left xEqY = withSomeSing dXsYs $ \(sDXsYs :: Sing dXsYs) ->+ elimDecision @_ @(ConstSym1 (Decision ((x:xs) :~: (y:ys)))) @dXsYs+ sDXsYs leftLeft leftRight+ where+ leftLeft :: forall (zz :: xs :~: ys).+ Sing zz -> Decision ((x:xs) :~: (y:ys))+ leftLeft xsEqYs = Proved $ intermixListEqs (fromSing xEqY) (fromSing xsEqYs)++ leftRight :: forall (r :: (xs :~: ys) ~> Void).+ Sing r -> Decision ((x:xs) :~: (y:ys))+ leftRight no = Disproved $ fromSing no . snd . injective++ right :: forall (r :: (x :~: y) ~> Void).+ Sing r -> Decision ((x:xs) :~: (y:ys))+ right no = Disproved $ fromSing no . fst . injective++ injective :: (x:xs) :~: (y:ys) -> (x :~: y, xs :~: ys)+ injective = consInjective @e @x @xs @y @ys sx sxs++decEqList :: forall (es1 :: [e]) (es2 :: [e]).+ (forall (e1 :: e) (e2 :: e).+ Sing e1 -> Sing e2 -> Decision (e1 :~: e2))+ -> Sing es1 -> Sing es2 -> Decision (es1 :~: es2)+decEqList f ses1 = runWhyDecEqList (elimList @e @(TyCon1 WhyDecEqList) @es1 ses1 base step)+ where+ base :: WhyDecEqList '[]+ base = WhyDecEqList decEqNil++ step :: forall (x :: e) (xs :: [e]).+ Sing x -> Sing xs+ -> WhyDecEqList xs+ -> WhyDecEqList (x:xs)+ step sx sxs swhyXs = WhyDecEqList $ \(sl :: Sing l) ->+ elimList @e @(WhyDecEqConsSym2 x xs) @l sl+ stepBase stepStep+ where+ stepBase :: Decision ((x:xs) :~: '[])+ stepBase = Disproved $ consNotNil @e @x @xs++ stepStep :: forall (y :: e) (ys :: [e]).+ Sing y -> Sing ys+ -> Decision ((x:xs) :~: ys)+ -> Decision ((x:xs) :~: (y:ys))+ stepStep sy sys _ = decCongCons sx sxs+ (f sx sy)+ (runWhyDecEqList swhyXs sys)
+ tests/DecideTypes.hs view
@@ -0,0 +1,106 @@+{-# LANGUAGE AllowAmbiguousTypes #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeInType #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE UndecidableInstances #-}+-- TODO: Remove this in the next version of singletons+{-# OPTIONS_GHC -Wno-orphans #-}+module DecideTypes where++import Data.Kind+import Data.Nat+import Data.Singletons.TH hiding (Decision(..))++-- TODO: Remove these in the next version of singletons+$(genSingletons [''Void])+$(genDefunSymbols [''(~>)])++-- Due to https://github.com/goldfirere/singletons/issues/82, promoting the+-- Decision data type from Data.Singletons.Decide is a tad awkward. To work+-- around these, we define a more general Decision' data type here.+data Decision' p a+ = Proved a+ | Disproved (p @@ a @@ Void)++elimDecision :: forall (a :: Type) (p :: PDecision a ~> Type) (d :: PDecision a).+ Sing d+ -> (forall (yes :: a). Sing yes -> p @@ (Proved yes))+ -> (forall (no :: a ~> Void). Sing no -> p @@ (Disproved no))+ -> p @@ d+elimDecision (SProved yes) pProved _ = pProved yes+elimDecision (SDisproved no) _ pDisproved = pDisproved no++instance Show a => Show (Decision' p a) where+ showsPrec p (Proved a) =+ showParen (p > 10) $ showString "Proved " . showsPrec 11 a+ showsPrec p (Disproved _) =+ showParen (p > 10) $ showString "Disproved <void>"++type Decision = Decision' (TyCon2 (->))+type PDecision = Decision' (:~>$)++data instance Sing (z :: PDecision a) where+ -- It would be lovely to not have to write those (:: PDecision a) kind+ -- ascriptions in the return types of each constructor.+ -- See https://ghc.haskell.org/trac/ghc/ticket/14111.+ SProved :: forall (x :: a). Sing x -> Sing (Proved x :: PDecision a)+ SDisproved :: forall (r :: a ~> Void). Sing r -> Sing (Disproved r :: PDecision a)++instance SingKind a => SingKind (PDecision a) where+ type Demote (PDecision a) = Decision (Demote a)+ fromSing (SProved a) = Proved (fromSing a)+ fromSing (SDisproved r) = Disproved (fromSing r)+ toSing (Proved x) = withSomeSing x $ SomeSing . SProved+ toSing (Disproved r) = withSomeSing r $ SomeSing . SDisproved++type family NatEqConsequences (a :: Nat) (b :: Nat) :: Type where+ NatEqConsequences Z Z = ()+ NatEqConsequences Z (S _) = Void+ NatEqConsequences (S _) Z = Void+ NatEqConsequences (S k1) (S k2) = k1 :~: k2+$(genDefunSymbols [''NatEqConsequences])++type WhyNatEqConsequencesSame (a :: Nat) = NatEqConsequences a a+$(genDefunSymbols [''WhyNatEqConsequencesSame])++type WhyDecEqZ (k :: Nat) = Decision (Z :~: k)+$(genDefunSymbols [''WhyDecEqZ])++type WhyDecEqS (n :: Nat) (k :: Nat) = Decision (S n :~: k)+$(genDefunSymbols [''WhyDecEqS])++-- The newtype wrapper is needed to work around+-- https://github.com/goldfirere/singletons/issues/198+newtype WhyDecEqNat (k :: Nat) = WhyDecEqNat+ { runWhyDecEqNat :: forall (j :: Nat). Sing j -> Decision (k :~: j) }++type family ListEqConsequences (xxs :: [e]) (yys :: [e]) :: Type where+ ListEqConsequences '[] '[] = ()+ ListEqConsequences '[] (_:_) = Void+ ListEqConsequences (_:_) '[] = Void+ ListEqConsequences (x:xs) (y:ys) = (x :~: y, xs :~: ys)+$(genDefunSymbols [''ListEqConsequences])++type WhyListEqConsequencesSame (es :: [e]) = ListEqConsequences es es+$(genDefunSymbols [''WhyListEqConsequencesSame])++type WhyDecEqNil (es :: [e]) = Decision ('[] :~: es)+$(genDefunSymbols [''WhyDecEqNil])++type WhyDecEqCons (x :: e) (xs :: [e]) (es :: [e]) = Decision ((x:xs) :~: es)+$(genDefunSymbols [''WhyDecEqCons])++type WhyIntermixListEqs1 (x :: e) (xs :: [e]) (ys :: [e]) (k :: e) = (x:xs) :~: (k:ys)+type WhyIntermixListEqs2 (x :: e) (xs :: [e]) (k :: [e]) = (x:xs) :~: (x:k)+$(genDefunSymbols [''WhyIntermixListEqs1, ''WhyIntermixListEqs2])++-- The newtype wrapper is needed to work around+-- https://github.com/goldfirere/singletons/issues/198+newtype WhyDecEqList (l1 :: [e]) = WhyDecEqList+ { runWhyDecEqList :: forall (l2 :: [e]). Sing l2 -> Decision (l1 :~: l2) }
tests/EqualitySpec.hs view
@@ -43,7 +43,9 @@ instance SingI Refl where sing = SRefl -(~>:~:) :: forall (k :: Type) (a :: k) (b :: k) (r :: a :~: b) (p :: forall (y :: k). a :~: y ~> Type).+(~>:~:) :: forall (k :: Type) (a :: k) (b :: k)+ (p :: forall (y :: k). a :~: y ~> Type)+ (r :: a :~: b). Sing r -> p @@ Refl -> p @@ r@@ -61,7 +63,9 @@ instance SingI HRefl where sing = SHRefl -(~>:~~:) :: forall (j :: Type) (k :: Type) (a :: j) (b :: k) (r :: a :~~: b) (p :: forall (z :: Type) (y :: z). a :~~: y ~> Type).+(~>:~~:) :: forall (j :: Type) (k :: Type) (a :: j) (b :: k)+ (p :: forall (z :: Type) (y :: z). a :~~: y ~> Type)+ (r :: a :~~: b). Sing r -> p @@ HRefl -> p @@ r@@ -77,7 +81,7 @@ sym :: forall (t :: Type) (a :: t) (b :: t). a :~: b -> b :~: a sym eq = withSomeSing eq $ \(singEq :: Sing r) ->- (~>:~:) @t @a @b @r @(WhySymSym a) singEq Refl+ (~>:~:) @t @a @b @(WhySymSym a) @r singEq Refl type WhyHsym (a :: j) (y :: z) (e :: a :~~: y) = y :~~: a data WhyHsymSym (a :: j) :: forall (z :: Type) (y :: z). a :~~: y ~> Type@@ -87,7 +91,7 @@ hsym :: forall (j :: Type) (k :: Type) (a :: j) (b :: k). a :~~: b -> b :~~: a hsym eq = withSomeSing eq $ \(singEq :: Sing r) ->- (~>:~~:) @j @k @a @b @r @(WhyHsymSym a) singEq HRefl+ (~>:~~:) @j @k @a @b @(WhyHsymSym a) @r singEq HRefl type family Symmetry (x :: (a :: k) :~: (b :: k)) :: b :~: a where Symmetry Refl = Refl@@ -101,7 +105,7 @@ symIdempotent :: forall (t :: Type) (a :: t) (b :: t) (e :: a :~: b). Sing e -> Symmetry (Symmetry e) :~: e-symIdempotent se = (~>:~:) @t @a @b @e @(WhySymIdempotentSym a) se Refl+symIdempotent se = (~>:~:) @t @a @b @(WhySymIdempotentSym a) @e se Refl type family Hsymmetry (x :: (a :: j) :~~: (b :: k)) :: b :~~: a where Hsymmetry HRefl = HRefl@@ -115,7 +119,7 @@ hsymIdempotent :: forall (j :: Type) (k :: Type) (a :: j) (b :: k) (e :: a :~~: b). Sing e -> Hsymmetry (Hsymmetry e) :~: e-hsymIdempotent se = (~>:~~:) @j @k @a @b @e @(WhyHsymIdempotentSym a) se Refl+hsymIdempotent se = (~>:~~:) @j @k @a @b @(WhyHsymIdempotentSym a) @e se Refl type WhyReplace (from :: t) (p :: t ~> Type) (y :: t) (e :: from :~: y) = p @@ y@@ -130,7 +134,7 @@ -> p @@ to replace from eq = withSomeSing eq $ \(singEq :: Sing r) ->- (~>:~:) @t @from @to @r @(WhyReplaceSym from p) singEq from+ (~>:~:) @t @from @to @(WhyReplaceSym from p) @r singEq from {- type WhyHreplace (from :: j) (p :: forall (z :: Type). z ~> Type)@@ -175,4 +179,22 @@ -> f @@ a :~: f @@ b cong eq = withSomeSing eq $ \(singEq :: Sing r) ->- (~>:~:) @x @a @b @r @(WhyCongSym x y f a) singEq Refl+ (~>:~:) @x @a @b @(WhyCongSym x y f a) @r singEq Refl++type WhyEqIsRefl (a :: k) (z :: k) (e :: a :~: z)+ = e :~~: (Refl :: a :~: a)+data WhyEqIsReflSym (a :: k) :: forall (z :: k). a :~: z ~> Type+type instance Apply (WhyEqIsReflSym a :: a :~: z ~> Type) e = WhyEqIsRefl a z e++eqIsRefl :: forall (k :: Type) (a :: k) (b :: k) (e :: a :~: b).+ Sing e -> e :~~: (Refl :: a :~: a)+eqIsRefl eq = (~>:~:) @k @a @b @(WhyEqIsReflSym a) @e eq HRefl++type WhyHEqIsHRefl (a :: j) (z :: k) (e :: a :~~: z)+ = e :~~: (HRefl :: a :~~: a)+data WhyHEqIsHReflSym (a :: j) :: forall (k :: Type) (z :: k). a :~~: z ~> Type+type instance Apply (WhyHEqIsHReflSym a :: a :~~: z ~> Type) e = WhyHEqIsHRefl a z e++heqIsHRefl :: forall (j :: Type) (k :: Type) (a :: j) (b :: k) (e :: a :~~: b).+ Sing e -> e :~~: (HRefl :: a :~~: a)+heqIsHRefl heq = (~>:~~:) @j @k @a @b @(WhyHEqIsHReflSym a) @e heq HRefl
− tests/PeanoSpec.hs
@@ -1,117 +0,0 @@-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE TypeApplications #-}-{-# LANGUAGE TypeInType #-}-{-# LANGUAGE TypeOperators #-}-module PeanoSpec where--import Data.Kind-import Data.Singletons--import PeanoTypes--import Test.Hspec--main :: IO ()-main = hspec spec--spec :: Spec-spec = parallel $ do- describe "replicateVec" $ do- it "works with empty lists" $- replicateVec SZ () `shouldBe` VNil- it "works with non-empty lists" $- replicateVec (SS SZ) () `shouldBe` () :# VNil- describe "mapVec" $ do- it "maps over a Vec" $ do- mapVec reverse ("hello" :# "world" :# VNil)- `shouldBe` ("olleh" :# "dlrow" :# VNil)- describe "zipWithVec" $ do- it "zips two Vecs" $ do- zipWithVec (,) ((2 :: Int) :# 22 :# VNil)- ("chicken-of-the-woods" :# "hen-of-woods" :# VNil)- `shouldBe` ((2, "chicken-of-the-woods") :# (22, "hen-of-woods")- :# VNil)- describe "appendVec" $ do- it "appends two Vecs" $ do- appendVec ("portabello" :# "bay-bolete"- :# "funnel-chantrelle"- :# VNil)- ("sheathed-woodtuft" :# "puffball" :# VNil)- `shouldBe` ("portabello" :# "bay-bolete"- :# "funnel-chantrelle"- :# "sheathed-woodtuft"- :# "puffball"- :# VNil)- describe "transposeVec" $ do- it "transposes a Vec" $ do- transposeVec (('a' :# 'b' :# 'c' :# VNil)- :# ('d' :# 'e' :# 'f' :# VNil)- :# VNil)- `shouldBe`- (('a' :# 'd' :# VNil)- :# ('b' :# 'e' :# VNil)- :# ('c' :# 'f' :# VNil)- :# VNil)---------replicateVec :: forall (e :: Type) (howMany :: Peano).- Sing howMany -> e -> Vec e howMany-replicateVec s e = elimPeano @(TyCon1 (Vec e)) @howMany s VNil step- where- step :: forall (k :: Peano). Sing k -> Vec e k -> Vec e (S k)- step _ = (e :#)--mapVec :: forall (a :: Type) (b :: Type) (n :: Peano).- SingI n- => (a -> b) -> Vec a n -> Vec b n-mapVec f = elimPeano @(WhyMapVecSym2 a b) @n (sing @_ @n) base step- where- base :: WhyMapVec a b Z- base _ = VNil-- step :: forall (k :: Peano). Sing k -> WhyMapVec a b k -> WhyMapVec a b (S k)- step _ mapK vK = f (vhead vK) :# mapK (vtail vK)--zipWithVec :: forall (a :: Type) (b :: Type) (c :: Type) (n :: Peano).- SingI n- => (a -> b -> c) -> Vec a n -> Vec b n -> Vec c n-zipWithVec f = elimPeano @(WhyZipWithVecSym3 a b c) @n (sing @_ @n) base step- where- base :: WhyZipWithVec a b c Z- base _ _ = VNil-- step :: forall (k :: Peano).- Sing k- -> WhyZipWithVec a b c k- -> WhyZipWithVec a b c (S k)- step _ zwK vaK vbK = f (vhead vaK) (vhead vbK)- :# zwK (vtail vaK) (vtail vbK)--appendVec :: forall (e :: Type) (n :: Peano) (m :: Peano).- SingI n- => Vec e n -> Vec e m -> Vec e (n `Plus` m)-appendVec = elimPeano @(WhyAppendVecSym2 e m) @n (sing @_ @n) base step- where- base :: WhyAppendVec e m Z- base _ = id-- step :: forall (k :: Peano).- Sing k- -> WhyAppendVec e m k- -> WhyAppendVec e m (S k)- step _ avK vK1 vK2 = vhead vK1 :# avK (vtail vK1) vK2--transposeVec :: forall (e :: Type) (n :: Peano) (m :: Peano).- (SingI n, SingI m)- => Vec (Vec e m) n -> Vec (Vec e n) m-transposeVec = elimPeano @(WhyTransposeVecSym2 e m) @n (sing @_ @n) base step- where- base :: WhyTransposeVec e m Z- base _ = replicateVec (sing @_ @m) VNil-- step :: forall (k :: Peano).- Sing k- -> WhyTransposeVec e m k- -> WhyTransposeVec e m (S k)- step _ transK vK = zipWithVec (:#) (vhead vK) (transK (vtail vK))
− tests/PeanoTypes.hs
@@ -1,94 +0,0 @@-{-# LANGUAGE AllowAmbiguousTypes #-}-{-# LANGUAGE GADTs #-}-{-# LANGUAGE RankNTypes #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE StandaloneDeriving #-}-{-# LANGUAGE TemplateHaskell #-}-{-# LANGUAGE TypeApplications #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE TypeInType #-}-{-# LANGUAGE TypeOperators #-}-{-# LANGUAGE UndecidableInstances #-}-module PeanoTypes where--import Data.Eliminator.TH-import Data.Kind-import Data.Singletons.TH--$(singletons [d|- data Peano = Z | S Peano-- infixl 6 `plus`- plus :: Peano -> Peano -> Peano- plus Z m = m- plus (S k) m = S (plus k m)-- infixl 7 `times`- times :: Peano -> Peano -> Peano- times Z _ = Z- times (S k) m = plus m (times k m)- |])-$(deriveElim ''Peano)--data Vec a (n :: Peano) where- VNil :: Vec a Z- (:#) :: { vhead :: a, vtail :: Vec a n } -> Vec a (S n)-infixr 5 :#-deriving instance Eq a => Eq (Vec a n)-deriving instance Ord a => Ord (Vec a n)-deriving instance Show a => Show (Vec a n)--data instance Sing (z :: Vec a n) where- SVNil :: Sing VNil- (:%#) :: { sVhead :: Sing x, sVtail :: Sing xs } -> Sing (x :# xs)-type SVec = (Sing :: Vec a n -> Type)-infixr 5 :%#--instance SingKind a => SingKind (Vec a n) where- type Demote (Vec a n) = Vec (Demote a) n- fromSing SVNil = VNil- fromSing (x :%# xs) = fromSing x :# fromSing xs- toSing VNil = SomeSing SVNil- toSing (x :# xs) =- withSomeSing x $ \sx ->- withSomeSing xs $ \sxs ->- SomeSing $ sx :%# sxs--instance SingI VNil where- sing = SVNil--instance (SingI x, SingI xs) => SingI (x :# xs) where- sing = sing :%# sing--elimVec :: forall (a :: Type) (n :: Peano)- (p :: forall (k :: Peano). Vec a k ~> Type) (v :: Vec a n).- Sing v- -> p @@ VNil- -> (forall (k :: Peano) (x :: a) (xs :: Vec a k).- Sing x -> Sing xs -> p @@ xs -> p @@ (x :# xs))- -> p @@ v-elimVec SVNil pVNil _ = pVNil-elimVec (sx :%# (sxs :: Sing (xs :: Vec a k))) pVNil pVCons =- pVCons sx sxs (elimVec @a @k @p @xs sxs pVNil pVCons)--type WhyMapVec (a :: Type) (b :: Type) (n :: Peano) = Vec a n -> Vec b n-$(genDefunSymbols [''WhyMapVec])--type WhyZipWithVec (a :: Type) (b :: Type) (c :: Type) (n :: Peano)- = Vec a n -> Vec b n -> Vec c n-$(genDefunSymbols [''WhyZipWithVec])--type WhyAppendVec (e :: Type) (m :: Peano) (n :: Peano)- = Vec e n -> Vec e m -> Vec e (n `Plus` m)-$(genDefunSymbols [''WhyAppendVec])--type WhyTransposeVec (e :: Type) (m :: Peano) (n :: Peano)- = Vec (Vec e m) n -> Vec (Vec e n) m-$(genDefunSymbols [''WhyTransposeVec])--type WhyConcatVec (e :: Type) (j :: Peano) (n :: Peano) (l :: Vec (Vec e j) n)- = Vec e (n `Times` j)-data WhyConcatVecSym (e :: Type) (j :: Peano)- :: forall (n :: Peano). Vec (Vec e j) n ~> Type-type instance Apply (WhyConcatVecSym e j :: Vec (Vec e j) n ~> Type) l- = WhyConcatVec e j n l
tests/VecSpec.hs view
@@ -5,11 +5,13 @@ {-# LANGUAGE TypeOperators #-} module VecSpec where +import Data.Eliminator import Data.Kind+import Data.Nat import Data.Singletons+import Data.Singletons.Prelude.Num -import PeanoSpec (appendVec)-import PeanoTypes+import VecTypes import Test.Hspec @@ -18,6 +20,43 @@ spec :: Spec spec = parallel $ do+ describe "replicateVec" $ do+ it "works with empty lists" $+ replicateVec (sLit @0) () `shouldBe` VNil+ it "works with non-empty lists" $ do+ replicateVec (sLit @1) () `shouldBe` () :# VNil+ replicateVec (sLit @2) () `shouldBe` () :# () :# VNil+ describe "mapVec" $ do+ it "maps over a Vec" $ do+ mapVec reverse ("hello" :# "world" :# VNil)+ `shouldBe` ("olleh" :# "dlrow" :# VNil)+ describe "zipWithVec" $ do+ it "zips two Vecs" $ do+ zipWithVec (,) ((2 :: Int) :# 22 :# VNil)+ ("chicken-of-the-woods" :# "hen-of-woods" :# VNil)+ `shouldBe` ((2, "chicken-of-the-woods") :# (22, "hen-of-woods")+ :# VNil)+ describe "appendVec" $ do+ it "appends two Vecs" $ do+ appendVec ("portabello" :# "bay-bolete"+ :# "funnel-chantrelle"+ :# VNil)+ ("sheathed-woodtuft" :# "puffball" :# VNil)+ `shouldBe` ("portabello" :# "bay-bolete"+ :# "funnel-chantrelle"+ :# "sheathed-woodtuft"+ :# "puffball"+ :# VNil)+ describe "transposeVec" $ do+ it "transposes a Vec" $ do+ transposeVec (('a' :# 'b' :# 'c' :# VNil)+ :# ('d' :# 'e' :# 'f' :# VNil)+ :# VNil)+ `shouldBe`+ (('a' :# 'd' :# VNil)+ :# ('b' :# 'e' :# VNil)+ :# ('c' :# 'f' :# VNil)+ :# VNil) describe "concatVec" $ do it "concats a Vec of Vecs" $ do concatVec ((False :# True :# False :# VNil)@@ -28,16 +67,77 @@ ----- -concatVec :: forall (e :: Type) (n :: Peano) (j :: Peano).+replicateVec :: forall (e :: Type) (howMany :: Nat).+ Sing howMany -> e -> Vec e howMany+replicateVec s e = elimNat @(TyCon1 (Vec e)) @howMany s VNil step+ where+ step :: forall (k :: Nat). Sing k -> Vec e k -> Vec e (S k)+ step _ = (e :#)++mapVec :: forall (a :: Type) (b :: Type) (n :: Nat).+ SingI n+ => (a -> b) -> Vec a n -> Vec b n+mapVec f = elimNat @(WhyMapVecSym2 a b) @n (sing @_ @n) base step+ where+ base :: WhyMapVec a b Z+ base _ = VNil++ step :: forall (k :: Nat). Sing k -> WhyMapVec a b k -> WhyMapVec a b (S k)+ step _ mapK vK = f (vhead vK) :# mapK (vtail vK)++zipWithVec :: forall (a :: Type) (b :: Type) (c :: Type) (n :: Nat).+ SingI n+ => (a -> b -> c) -> Vec a n -> Vec b n -> Vec c n+zipWithVec f = elimNat @(WhyZipWithVecSym3 a b c) @n (sing @_ @n) base step+ where+ base :: WhyZipWithVec a b c Z+ base _ _ = VNil++ step :: forall (k :: Nat).+ Sing k+ -> WhyZipWithVec a b c k+ -> WhyZipWithVec a b c (S k)+ step _ zwK vaK vbK = f (vhead vaK) (vhead vbK)+ :# zwK (vtail vaK) (vtail vbK)++appendVec :: forall (e :: Type) (n :: Nat) (m :: Nat).+ SingI n+ => Vec e n -> Vec e m -> Vec e (n :+ m)+appendVec = elimNat @(WhyAppendVecSym2 e m) @n (sing @_ @n) base step+ where+ base :: WhyAppendVec e m Z+ base _ = id++ step :: forall (k :: Nat).+ Sing k+ -> WhyAppendVec e m k+ -> WhyAppendVec e m (S k)+ step _ avK vK1 vK2 = vhead vK1 :# avK (vtail vK1) vK2++transposeVec :: forall (e :: Type) (n :: Nat) (m :: Nat).+ (SingI n, SingI m)+ => Vec (Vec e m) n -> Vec (Vec e n) m+transposeVec = elimNat @(WhyTransposeVecSym2 e m) @n (sing @_ @n) base step+ where+ base :: WhyTransposeVec e m Z+ base _ = replicateVec (sing @_ @m) VNil++ step :: forall (k :: Nat).+ Sing k+ -> WhyTransposeVec e m k+ -> WhyTransposeVec e m (S k)+ step _ transK vK = zipWithVec (:#) (vhead vK) (transK (vtail vK))++concatVec :: forall (e :: Type) (n :: Nat) (j :: Nat). (SingKind e, SingI j, e ~ Demote e)- => Vec (Vec e j) n -> Vec e (n `Times` j)+ => Vec (Vec e j) n -> Vec e (n :* j) concatVec l = withSomeSing l $ \(singL :: Sing l) -> elimVec @(Vec e j) @n @(WhyConcatVecSym e j) @l singL base step where base :: WhyConcatVec e j Z VNil base = VNil - step :: forall (k :: Peano) (x :: Vec e j) (xs :: Vec (Vec e j) k).+ step :: forall (k :: Nat) (x :: Vec e j) (xs :: Vec (Vec e j) k). Sing x -> Sing xs -> WhyConcatVec e j k xs -> WhyConcatVec e j (S k) (x :# xs)
+ tests/VecTypes.hs view
@@ -0,0 +1,80 @@+{-# LANGUAGE AllowAmbiguousTypes #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE StandaloneDeriving #-}+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeInType #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE UndecidableInstances #-}+module VecTypes where++import Data.Kind+import Data.Nat+import Data.Singletons.Prelude.Num+import Data.Singletons.TH++data Vec :: Type -> Nat -> Type where+ VNil :: Vec a Z+ (:#) :: { vhead :: a, vtail :: Vec a n } -> Vec a (S n)+infixr 5 :#+deriving instance Eq a => Eq (Vec a n)+deriving instance Ord a => Ord (Vec a n)+deriving instance Show a => Show (Vec a n)++data instance Sing (z :: Vec a n) where+ SVNil :: Sing VNil+ (:%#) :: { sVhead :: Sing x, sVtail :: Sing xs } -> Sing (x :# xs)+type SVec = (Sing :: Vec a n -> Type)+infixr 5 :%#++instance SingKind a => SingKind (Vec a n) where+ type Demote (Vec a n) = Vec (Demote a) n+ fromSing SVNil = VNil+ fromSing (x :%# xs) = fromSing x :# fromSing xs+ toSing VNil = SomeSing SVNil+ toSing (x :# xs) =+ withSomeSing x $ \sx ->+ withSomeSing xs $ \sxs ->+ SomeSing $ sx :%# sxs++instance SingI VNil where+ sing = SVNil++instance (SingI x, SingI xs) => SingI (x :# xs) where+ sing = sing :%# sing++elimVec :: forall (a :: Type) (n :: Nat)+ (p :: forall (k :: Nat). Vec a k ~> Type) (v :: Vec a n).+ Sing v+ -> p @@ VNil+ -> (forall (k :: Nat) (x :: a) (xs :: Vec a k).+ Sing x -> Sing xs -> p @@ xs -> p @@ (x :# xs))+ -> p @@ v+elimVec SVNil pVNil _ = pVNil+elimVec (sx :%# (sxs :: Sing (xs :: Vec a k))) pVNil pVCons =+ pVCons sx sxs (elimVec @a @k @p @xs sxs pVNil pVCons)++type WhyMapVec (a :: Type) (b :: Type) (n :: Nat) = Vec a n -> Vec b n+$(genDefunSymbols [''WhyMapVec])++type WhyZipWithVec (a :: Type) (b :: Type) (c :: Type) (n :: Nat)+ = Vec a n -> Vec b n -> Vec c n+$(genDefunSymbols [''WhyZipWithVec])++type WhyAppendVec (e :: Type) (m :: Nat) (n :: Nat)+ = Vec e n -> Vec e m -> Vec e (n :+ m)+$(genDefunSymbols [''WhyAppendVec])++type WhyTransposeVec (e :: Type) (m :: Nat) (n :: Nat)+ = Vec (Vec e m) n -> Vec (Vec e n) m+$(genDefunSymbols [''WhyTransposeVec])++type WhyConcatVec (e :: Type) (j :: Nat) (n :: Nat) (l :: Vec (Vec e j) n)+ = Vec e (n :* j)+data WhyConcatVecSym (e :: Type) (j :: Nat)+ :: forall (n :: Nat). Vec (Vec e j) n ~> Type+type instance Apply (WhyConcatVecSym e j :: Vec (Vec e j) n ~> Type) l+ = WhyConcatVec e j n l