Guest User

Untitled

a guest
Oct 23rd, 2018
85
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 4.93 KB | None | 0 0
  1. {-# LANGUAGE DataKinds #-}
  2. {-# LANGUAGE GADTs #-}
  3. {-# LANGUAGE PolyKinds #-}
  4. {-# LANGUAGE RankNTypes #-}
  5. {-# LANGUAGE ScopedTypeVariables #-}
  6. {-# LANGUAGE StandaloneDeriving #-}
  7. {-# LANGUAGE TypeApplications #-}
  8. {-# LANGUAGE TypeFamilies #-}
  9. {-# LANGUAGE TypeFamilyDependencies #-}
  10. {-# LANGUAGE TypeInType #-}
  11. {-# LANGUAGE TypeOperators #-}
  12. {-# LANGUAGE UndecidableInstances #-}
  13.  
  14. -- | Testing dependent functions
  15. module Test.DepFn (
  16. -- * Infrastructure: singletons
  17. Sing(..)
  18. , SingI(..)
  19. , SomeSing(..)
  20. , withSomeSing
  21. , SingKind(..)
  22. -- * Infrastructure: generic
  23. , All
  24. -- * Testing dependent functions
  25. , DepArgs(..)
  26. , DepFn(..)
  27. ) where
  28.  
  29. import Data.Kind (Constraint, Type)
  30. import Test.QuickCheck
  31.  
  32. {-------------------------------------------------------------------------------
  33. Excerpt from singletons
  34. -------------------------------------------------------------------------------}
  35.  
  36. data family Sing (a :: k)
  37.  
  38. -- | Singletons for lists
  39. --
  40. -- NOTE: Unlike the singletons library, we do /not/ require instances for the
  41. -- elements of the list.
  42. data instance Sing (xs :: [k]) where
  43. SNil :: Sing '[]
  44. SCons :: Sing xs -> Sing (x ': xs)
  45.  
  46. class SingI (a :: k) where
  47. sing :: Sing a
  48.  
  49. instance SingI '[] where sing = SNil
  50. instance SingI xs => SingI (x ': xs) where sing = SCons sing
  51.  
  52. data SomeSing k where
  53. SomeSing :: Sing (a :: k) -> SomeSing k
  54.  
  55. withSomeSing :: forall k r. SingKind k
  56. => Demote k
  57. -> (forall (a :: k). Sing a -> r)
  58. -> r
  59. withSomeSing d k = case toSing @k d :: SomeSing k of
  60. SomeSing s -> k s
  61.  
  62. class SingKind k where
  63. type Demote k = (r :: Type) | r -> k
  64.  
  65. fromSing :: Sing (a :: k) -> Demote k
  66. toSing :: Demote k -> SomeSing k
  67.  
  68. {-------------------------------------------------------------------------------
  69. Generic auxiliary
  70. -------------------------------------------------------------------------------}
  71.  
  72. type family All (f :: k -> Constraint) (xs :: [k]) :: Constraint where
  73. All _ '[] = ()
  74. All f (x ': xs) = (f x, All f xs)
  75.  
  76. {-------------------------------------------------------------------------------
  77. 'Testable' support for dependently typed functions
  78. -------------------------------------------------------------------------------}
  79.  
  80. data DepArgs :: [k -> Type] -> k -> Type where
  81. Nil :: DepArgs '[] t
  82. (:*) :: f t -> DepArgs fs t -> DepArgs (f ': fs) t
  83.  
  84. infixr :*
  85.  
  86. newtype DepFn (fs :: [k -> Type]) a = DepFn {
  87. applyDepFn :: forall (t :: k). Sing (t :: k) -> DepArgs fs t -> a
  88. }
  89.  
  90. class SingArbitrary (f :: k -> Type) where
  91. singArbitrary :: Sing t -> Gen (f t)
  92.  
  93. class SingShow (f :: k -> Type) where
  94. singShow :: Sing t -> f t -> String
  95.  
  96. instance (All SingArbitrary fs, SingI fs) => SingArbitrary (DepArgs fs) where
  97. singArbitrary (st :: Sing t) = go sing
  98. where
  99. go :: All SingArbitrary fs' => Sing fs' -> Gen (DepArgs fs' t)
  100. go SNil = return Nil
  101. go (SCons ss) = (:*) <$> singArbitrary st <*> go ss
  102.  
  103. instance All SingShow fs => SingShow (DepArgs fs) where
  104. singShow _ Nil = "[]"
  105. singShow (st :: Sing t) (x :* xs) = "[" ++ singShow st x ++ go xs
  106. where
  107. go :: All SingShow fs' => DepArgs fs' t -> String
  108. go Nil = "]"
  109. go (x' :* xs') = "," ++ singShow st x' ++ go xs'
  110.  
  111. instance ( SingKind k
  112. , Arbitrary (Demote k)
  113. , All SingArbitrary fs
  114. , All SingShow fs
  115. , SingI fs
  116. , Testable a
  117. ) => Testable (DepFn (fs :: [k -> Type]) a) where
  118. property (DepFn f) = property $ do
  119. t :: Demote k <- arbitrary
  120. withSomeSing t $ \st -> do
  121. args <- singArbitrary st
  122. return $ counterexample (singShow st args) $ property (f st args)
  123.  
  124. {-------------------------------------------------------------------------------
  125. Example
  126. -------------------------------------------------------------------------------}
  127.  
  128. data Univ = Two | Many
  129.  
  130. instance Arbitrary Univ where
  131. arbitrary = elements [Two, Many]
  132.  
  133. data instance Sing (k :: Univ) where
  134. SingTwo :: Sing ('Two :: Univ)
  135. SingMany :: Sing ('Many :: Univ)
  136.  
  137. instance SingI ('Two :: Univ) where sing = SingTwo
  138. instance SingI ('Many :: Univ) where sing = SingMany
  139.  
  140. instance SingKind Univ where
  141. type Demote Univ = Univ
  142.  
  143. fromSing SingTwo = Two
  144. fromSing SingMany = Many
  145.  
  146. toSing Two = SomeSing SingTwo
  147. toSing Many = SomeSing SingMany
  148.  
  149. data Val :: Univ -> Type where
  150. ValTwo :: Bool -> Val 'Two
  151. ValMany :: Int -> Val 'Many
  152.  
  153. deriving instance Show (Val t)
  154.  
  155. instance Eq (Val t) where
  156. ValTwo x == ValTwo y = x == y
  157. ValMany x == ValMany y = x == y
  158.  
  159. instance SingShow Val where
  160. singShow _ = show
  161.  
  162. instance SingArbitrary Val where
  163. singArbitrary SingTwo = ValTwo <$> arbitrary
  164. singArbitrary SingMany = ValMany <$> arbitrary
  165.  
  166. prop_example :: DepFn '[Val, Val] Bool
  167. prop_example = DepFn $ \_sing (x :* y :* Nil) -> x == y
  168.  
  169. _example :: IO ()
  170. _example = quickCheck prop_example
Add Comment
Please, Sign In to add comment