packages feed

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 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