speculate 0.2.4 → 0.2.5
raw patch · 14 files changed
+436/−305 lines, 14 filesdep ~leancheck
Dependency ranges changed: leancheck
Files
- README.md +3/−0
- TODO.md +12/−1
- speculate.cabal +5/−5
- src/Test/Speculate/Expr.hs +2/−2
- src/Test/Speculate/Expr/Canon.hs +1/−1
- src/Test/Speculate/Expr/Core.hs +39/−2
- src/Test/Speculate/Expr/Equate.hs +1/−1
- src/Test/Speculate/Expr/Ground.hs +1/−1
- src/Test/Speculate/Expr/Instance.hs +261/−0
- src/Test/Speculate/Expr/Match.hs +36/−15
- src/Test/Speculate/Expr/TypeInfo.hs +0/−255
- src/Test/Speculate/Utils/Typeable.hs +1/−1
- tests/Test.hs +62/−4
- tests/test-expr.hs +12/−17
README.md view
@@ -144,6 +144,9 @@ For more examples, see the [eg](eg) and [bench](bench) folders. +Speculate has been subject to a paper, see the+[(Draft) Paper about Speculate (to appear) on Haskell Symposium 2017](https://matela.com.br/paper/speculate.pdf).+ [leancheck]: https://hackage.haskell.org/package/leancheck [LeanCheck]: https://hackage.haskell.org/package/leancheck [QuickSpec]: https://github.com/nick8325/quickspec
TODO.md view
@@ -24,7 +24,18 @@ ":". +isolate most of the Expr module+------------------------------- +Maybe most of the `Expr` module could be isolated from the rest of Speculate+and released as a separate package.++I'll have to see how it goes in other modules, specially the `grounds`+function. Which could be interesting to include in the "expr" package but+would still depend on Listable and LeanCheck (maybe make it depend on it+anyway...)++ later ----- @@ -149,7 +160,7 @@ * (for interface) I actually do not need to provide 0-argument constants in the background algebra. Since I am using an enumerative strategy, I can actually- enumerate those from the TypeInfo. This way, background will look nicer,+ enumerate those from `Instances`. This way, background will look nicer, with less functions and values. Computing the size of values and expressions may be a problem.
speculate.cabal view
@@ -1,5 +1,5 @@ name: speculate-version: 0.2.4+version: 0.2.5 synopsis: discovery of properties about Haskell functions description: Speculate automatically discovers laws about Haskell functions.@@ -18,7 +18,7 @@ maintainer: Rudy Matela <rudy@matela.com.br> category: Testing build-type: Simple-cabal-version: >=1.10+cabal-version: >=1.18 extra-doc-files: README.md , TODO.md@@ -31,7 +31,7 @@ source-repository this type: git location: https://github.com/rudymatela/speculate- tag: v0.2.4+ tag: v0.2.5 library@@ -44,8 +44,8 @@ , Test.Speculate.Expr.Core , Test.Speculate.Expr.Equate , Test.Speculate.Expr.Ground+ , Test.Speculate.Expr.Instance , Test.Speculate.Expr.Match- , Test.Speculate.Expr.TypeInfo , Test.Speculate.Pretty , Test.Speculate.Reason , Test.Speculate.Reason.Order@@ -67,7 +67,7 @@ , Test.Speculate.Utils.Timeout , Test.Speculate.Utils.Tuple , Test.Speculate.Utils.Typeable- build-depends: base >= 4 && < 5, leancheck >= 0.6.1, cmdargs, containers+ build-depends: base >= 4 && < 5, leancheck >= 0.6.3, cmdargs, containers hs-source-dirs: src default-language: Haskell2010
src/Test/Speculate/Expr.hs view
@@ -11,7 +11,7 @@ ( module Test.Speculate.Expr.Core , module Test.Speculate.Expr.Ground , module Test.Speculate.Expr.Match- , module Test.Speculate.Expr.TypeInfo+ , module Test.Speculate.Expr.Instance , module Test.Speculate.Expr.Equate , module Test.Speculate.Expr.Canon )@@ -20,6 +20,6 @@ import Test.Speculate.Expr.Core import Test.Speculate.Expr.Ground import Test.Speculate.Expr.Match-import Test.Speculate.Expr.TypeInfo+import Test.Speculate.Expr.Instance import Test.Speculate.Expr.Equate import Test.Speculate.Expr.Canon
src/Test/Speculate/Expr/Canon.hs view
@@ -16,7 +16,7 @@ import Test.Speculate.Expr.Core import Test.Speculate.Expr.Match-import Test.Speculate.Expr.TypeInfo+import Test.Speculate.Expr.Instance import Data.List ((\\)) -- | Canonicalize variable names in an expression.
src/Test/Speculate/Expr/Core.hs view
@@ -7,6 +7,7 @@ -- This module is part of Speculate. -- -- Defines the 'Expr' type and basic operations on it.+{-# LANGUAGE DeriveDataTypeable #-} -- for GHC < 7.10 module Test.Speculate.Expr.Core ( Expr (..) -- * Smart constructors@@ -76,6 +77,7 @@ data Expr = Constant String Dynamic | Var String TypeRep | Expr :$ Expr+ deriving Typeable -- for GHC < 7.10 -- | Encode a constant Haskell expression for use by Speculate. -- It takes a string representation of a value and a value, returning an@@ -145,12 +147,33 @@ where sp = if atomic s then isInfix s else maybe True (d >) $ outernmostPrec s showsPrecExpr d (Var "" _) = showString "_" -- a hole showsPrecExpr d (Var s _) = showParen (isInfix s) $ showString s+showsPrecExpr d ((Constant ":" _ :$ e1@(Constant _ _)) :$ e2)+ | typ e1 == typeOf (undefined :: Char) =+ case showsTailExpr e2 "" of+ '\"':cs -> showString ("\"" ++ (init . tail) (showsPrecExpr 0 e1 "") ++ cs)+ cs -> showParen (d > prec ":")+ $ showsOpExpr ":" e1 . showString ":" . showString cs showsPrecExpr d ((Constant ":" _ :$ e1) :$ e2) =- case showsPrecExpr 0 e2 "" of+ case showsTailExpr e2 "" of "[]" -> showString "[" . showsPrecExpr 0 e1 . showString "]" '[':cs -> showString "[" . showsPrecExpr 0 e1 . showString "," . showString cs cs -> showParen (d > prec ":")- $ showsOpExpr ":" e1 . showString ":" . showsOpExpr ":" e2+ $ showsOpExpr ":" e1 . showString ":" . showString cs+showsPrecExpr d ((Constant "," _ :$ e1) :$ e2) =+ showString "(" . showsPrecExpr 0 e1+ . showString "," . showsPrecExpr 0 e2+ . showString ")"+showsPrecExpr d (((Constant ",," _ :$ e1) :$ e2) :$ e3) =+ showString "(" . showsPrecExpr 0 e1+ . showString "," . showsPrecExpr 0 e2+ . showString "," . showsPrecExpr 0 e3+ . showString ")"+showsPrecExpr d ((((Constant ",,," _ :$ e1) :$ e2) :$ e3) :$ e4) =+ showString "(" . showsPrecExpr 0 e1+ . showString "," . showsPrecExpr 0 e2+ . showString "," . showsPrecExpr 0 e3+ . showString "," . showsPrecExpr 0 e4+ . showString ")" showsPrecExpr d ((Constant f _ :$ e1) :$ e2) | isInfix f = showParen (d > prec f) $ showsOpExpr f e1@@ -167,6 +190,20 @@ $ showsPrecExpr (prec " ") e1 . showString " " . showsPrecExpr (prec " " + 1) e2++-- bad smell here, repeated code!+showsTailExpr :: Expr -> String -> String+showsTailExpr ((Constant ":" _ :$ e1@(Constant _ _)) :$ e2)+ | typ e1 == typeOf (undefined :: Char) =+ case showsPrecExpr 0 e2 "" of+ '\"':cs -> showString ("\"" ++ (init . tail) (showsPrecExpr 0 e1 "") ++ cs)+ cs -> showsOpExpr ":" e1 . showString ":" . showsTailExpr e2+showsTailExpr ((Constant ":" _ :$ e1) :$ e2) =+ case showsPrecExpr 0 e2 "" of+ "[]" -> showString "[" . showsPrecExpr 0 e1 . showString "]"+ '[':cs -> showString "[" . showsPrecExpr 0 e1 . showString "," . showString cs+ cs -> showsOpExpr ":" e1 . showString ":" . showsTailExpr e2+showsTailExpr e = showsOpExpr ":" e showsOpExpr :: String -> Expr -> String -> String showsOpExpr op = showsPrecExpr (prec op + 1)
src/Test/Speculate/Expr/Equate.hs view
@@ -30,7 +30,7 @@ import Data.List ((\\)) import Test.Speculate.Utils import Test.Speculate.Expr.Core-import Test.Speculate.Expr.TypeInfo+import Test.Speculate.Expr.Instance equation :: Instances -> Expr -> Expr -> Maybe Expr equation ti e1 e2 = do
src/Test/Speculate/Expr/Ground.hs view
@@ -26,7 +26,7 @@ import Test.Speculate.Expr.Core import Test.Speculate.Expr.Match-import Test.Speculate.Expr.TypeInfo+import Test.Speculate.Expr.Instance import Test.Speculate.Expr.Equate import Test.LeanCheck import Data.Ratio
+ src/Test/Speculate/Expr/Instance.hs view
@@ -0,0 +1,261 @@+{-# Language DeriveDataTypeable, StandaloneDeriving #-} -- for GHC <= 7.8+-- |+-- Module : Test.Speculate.Expr.Instance+-- Copyright : (c) 2016-2017 Rudy Matela+-- License : 3-Clause BSD (see the file LICENSE)+-- Maintainer : Rudy Matela <rudy@matela.com.br>+--+-- This module is part of Speculate.+--+-- Typeclass instance information.+module Test.Speculate.Expr.Instance+ ( Instances+ , Instance (..)+ , TypeRep++ -- * Smart constructors+ , ins+ , eq, eqWith+ , ord, ordWith+ , eqOrd+ , listable, listableWith+ , name++ -- * Queries on Instances+ , instanceType+ , findInfo+ , names+ , eqE, isEq, isEqE+ , leE, ltE, isOrd, isOrdE+ , isEqOrd, isEqOrdE+ , tiersE, isListable++ -- * Type info for standard Haskell types+ , preludeInstances++ -- * Does not belong here?+ , defNames++ , boolTy+ , mkEqnTy+ )+where++import Test.Speculate.Expr.Core+import Test.Speculate.Expr.Match+import Test.Speculate.Utils hiding (ord)+import Test.LeanCheck+import Test.LeanCheck.Utils hiding (comparison)+import Test.LeanCheck.Error (errorToFalse)+import Data.Dynamic++import Data.Maybe (isJust,fromMaybe,listToMaybe,catMaybes,mapMaybe)+import Data.List (find,(\\))+import Data.Monoid ((<>))+++-- | Type information needed to Speculate expressions (single type / single class).+data Instance = Instance String TypeRep [Expr]+ deriving Show++instance Eq Instance where+ Instance s1 t1 _ == Instance s2 t2 _ = s1 == s2 && t1 == t2++instance Ord Instance where+ Instance s1 t1 _ `compare` Instance s2 t2 _ = s1 `compare` s2 <> t1 `compare` t2+++-- | Type information needed to Speculate expressions.+type Instances = [Instance]++instanceType :: Instance -> TypeRep+instanceType (Instance _ t _) = t++-- | Usage: @ins1 "x" (undefined :: Type)@+ins1 :: (Typeable a, Listable a, Show a, Eq a, Ord a)+ => String -> a -> Instances+ins1 n x = eq x ++ ord x ++ listable x ++ name n x++ins :: (Typeable a, Listable a, Show a, Eq a, Ord a)+ => String -> a -> Instances+ins n x = concat+ [ x / n++ , [x] / n ++ "s"+ , [[x]] / n ++ "ss"+--, [[[x]]] / n ++ "ss"++ , (x,x) / n ++ m+ , (x,x,x) / n ++ m ++ o+--, (x,x,x,x) / n ++ m ++ o ++ p++ , [(x,x)] / n ++ m ++ "s"+--, [(x,x,x)] / n ++ m ++ o ++ "ss"++--, (x,[x]) / n ++ m ++ "s"+--, ([x],x) / n ++ "s" ++ m+--, ([x],[x]) / n ++ "s" ++ m ++ "s"+--, (x,(x,x)) / n ++ m ++ o+--, ((x,x),x) / n ++ m ++ o++ , mayb x / "m" ++ n ++ "1"+--, eith x x / "e" ++ n ++ o ++ "1"+ ]+ where+ (/) :: (Typeable a, Listable a, Show a, Eq a, Ord a)+ => a -> String -> Instances -- monomorphism restriction strikes again+ (/) = flip ins1+ infixr 0 /+ m = namesFromTemplate n !! 1+ o = namesFromTemplate m !! 1+ p = namesFromTemplate o !! 1+-- NOTE: the function typeInfoN is not perfect: it won't help produce types+-- combining different sub-types, like for example: (Bool,Int). But it is+-- way better than the original version in which I had to explictly define+-- everything. A definitive solution is still to be thought of.+-- NOTE: see related TODO on the definition of basicInstances++eq :: (Typeable a, Eq a) => a -> Instances+eq x = eqWith $ (==) -:> x++ord :: (Typeable a, Ord a) => a -> Instances+ord x = ordWith $ (<=) -:> x++eqOrd :: (Typeable a, Eq a, Ord a) => a -> Instances+eqOrd x = eq x ++ ord x++listable :: (Typeable a, Show a, Listable a) => a -> Instances+listable x = listableWith $ tiers `asTypeOf` [[x]]++name :: Typeable a => String -> a -> Instances+name n x = [ Instance "Names" (typeOf x)+ [constant "names" $ namesFromTemplate n] ]++eqWith :: (Typeable a, Eq a) => (a -> a -> Bool) -> Instances+eqWith (==) = [ Instance "Eq" (typeOf $ arg (==))+ [constant "==" $ errorToFalse .: (==)] ]+ where+ arg :: (a -> b) -> a+ arg _ = undefined++ordWith :: (Typeable a, Ord a) => (a -> a -> Bool) -> Instances+ordWith (<=) = [ Instance "Ord" (typeOf $ arg (<=))+ [ constant "<=" $ errorToFalse .: (<=)+ , constant "<" $ (errorToFalse . not) .: flip (<=) ] ]+ where+ arg :: (a -> b) -> a+ arg _ = undefined++listableWith :: (Typeable a, Show a) => [[a]] -> Instances+listableWith xss = [ Instance "Listable" (typeOf $ head $ head xss)+ [constant "tiers" $ mapT showConstant xss] ]++isEq :: Instances -> TypeRep -> Bool+isEq ti = isJust . eqE ti++isOrd :: Instances -> TypeRep -> Bool+isOrd ti = isJust . ltE ti++isEqOrd :: Instances -> TypeRep -> Bool+isEqOrd ti t = isOrd ti t && isEq ti t++isEqE :: Instances -> Expr -> Bool+isEqE ti = isEq ti . typ++isOrdE :: Instances -> Expr -> Bool+isOrdE ti = isOrd ti . typ++isEqOrdE :: Instances -> Expr -> Bool+isEqOrdE ti = isEqOrd ti . typ++isListable :: Instances -> TypeRep -> Bool+isListable ti t = isJust $ findInfo m ti+ where+ m (Instance "Listable" t' ts) | t' == t = Just ts+ m _ = Nothing++-- TODO: implement above using something similar to the following+-- isComparable ti = isJust . (`findInfo` ti) . typ++findInfo :: (Instance -> Maybe a) -> Instances -> Maybe a+findInfo may = listToMaybe . mapMaybe may++findInfoOr :: a -> (Instance -> Maybe a) -> Instances -> a+findInfoOr def may = fromMaybe def . findInfo may++names :: Instances -> TypeRep -> [String]+names ti t = findInfoOr defNames m ti+ where+ m (Instance "Names" t' [ns]) | t == t' = Just $ eval defNames ns+ m _ = Nothing++tiersE :: Instances -> TypeRep -> [[Expr]]+tiersE ti t = findInfoOr (error $ "could not find Listable " ++ show t) m ti+ where+ m (Instance "Listable" t' [ts]) | t == t' = Just $ eval (error $ "invalid Listable " ++ show t) ts+ m _ = Nothing++eqE :: Instances -> TypeRep -> Maybe Expr+eqE ti t = findInfo m ti+ where+ m (Instance "Eq" t' [eq]) | t == t' = Just eq+ m _ = Nothing++ltE :: Instances -> TypeRep -> Maybe Expr+ltE ti t = findInfo m ti+ where+ m (Instance "Ord" t' [_,lt]) | t == t' = Just lt+ m _ = Nothing++leE :: Instances -> TypeRep -> Maybe Expr+leE ti t = findInfo m ti+ where+ m (Instance "Ord" t' [le,_]) | t == t' = Just le+ m _ = Nothing++deriving instance Typeable Word2 -- for GHC <= 7.8++-- TODO: include *ALL* prelude types on basicInstances+preludeInstances :: Instances+preludeInstances = concat+ [ ins1 "x" (undefined :: ())+ , ins1 "xs" (undefined :: [()])++ , ins "p" (undefined :: Bool)++ , ins "x" (undefined :: Int)+--, ins "x" (undefined :: Word)+ , ins "x" (undefined :: Integer)++ , ins "o" (undefined :: Ordering)+ , ins "c" (undefined :: Char)++ , ins "q" (undefined :: Rational)+ , ins "f" (undefined :: Float)+ , ins "f" (undefined :: Double)++-- TODO: uncomment the following and investigate why compilation takes so long+--, ins "x" (undefined :: Int1)+--, ins "x" (undefined :: Int2)+--, ins "x" (undefined :: Int3)+--, ins "x" (undefined :: Int4)+--, ins "x" (undefined :: Word1)+ , ins "x" (undefined :: Word2)+--, ins "x" (undefined :: Word3)+--, ins "x" (undefined :: Word4)+--, ins "x" (undefined :: Nat1)+--, ins "x" (undefined :: Nat2)+--, ins "x" (undefined :: Nat3)+--, ins "x" (undefined :: Nat4)+--, ins "x" (undefined :: Nat5)+--, ins "x" (undefined :: Nat6)+--, ins "x" (undefined :: Nat7)+ ]+-- WHOA! Have I discovered a "bug" in GHC? adding to many type compositions+-- on ins and types on preludeInstances makes compilation of this module+-- *really* slow: it takes a whopping 2 minutes!+-- (the above report is using -O2, I have not tested without optimizations).+++defNames :: [String]+defNames = namesFromTemplate "x"
src/Test/Speculate/Expr/Match.hs view
@@ -150,24 +150,45 @@ | otherwise = const Nothing unify :: Expr -> Expr -> Maybe Expr-unify e1 e2 = (e1' `assigning`) <$> unification e1' e2'- where- e1' = renameBy (++ "1") e1- e2' = renameBy (++ "2") e2+unify e1 e2 = (e1 `assigning`) <$> unification e1 e2 --- NOTE: Take care of passing disjoing variable namespaces on both expressions!--- see unify for an example of that. unification :: Expr -> Expr -> Maybe Binds-unification e1' e2' = u e1' e2' []+unification = naiveUnification++findBind :: Expr -> Expr -> Either Bool (String,Expr)+findBind e1 e2 | typ e1 /= typ e2 = Left False+ | e1 == e2 = Left True+findBind (Var s t) e2 = Right (s,e2)+findBind e1 (Var s t) = Right (s,e1)+findBind (f1 :$ x1) (f2 :$ x2) = case findBind f1 f2 of+ Left True -> findBind x1 x2+ r -> r+findBind e1 e2 = Left (e1 == e2)++-- NOTE: there are faster methods for unification.+naiveUnification :: Expr -> Expr -> Maybe Binds+naiveUnification e1' e2' = uu e1' e2' [] where- u :: Expr -> Expr -> Binds -> Maybe Binds- u e1 e2 | typ e1 /= typ e2 = const Nothing- u e1@(Var s1 t1) e2@(Var s2 t2) = updateAssignments s1 e2 >=> updateAssignments s2 e1- u e1 (Var s t) = updateAssignments s e1- u (Var s t) e2 = updateAssignments s e2- u (f1 :$ x1) (f2 :$ x2) = u f1 f2 >=> u x1 x2- u e1 e2 | e1 == e2 = Just- | otherwise = const Nothing+ uu :: Expr -> Expr -> Binds -> Maybe Binds+ uu e1' e2' bs' =+ case u e1' e2' bs' of+ Nothing -> Nothing+ Just (e1,e2,bs) ->+ if e1' == e1 && e2' == e2+ then Just bs+ else uu e1 e2 bs+ u :: Expr -> Expr -> Binds -> Maybe (Expr,Expr,Binds)+ u e1 e2 bs =+ case findBind e1 e2 of+ Left False -> Nothing+ Left True -> Just (e1,e2,bs)+ Right (s,e) ->+ if (Var s (typ e)) `isSub` e+ then Nothing+ else Just ( e1 `assigning` [(s,e)]+ , e2 `assigning` [(s,e)]+ , (s,e):[(s',e' `assigning` [(s,e)]) | (s',e') <- bs]+ ) -- 0 `isInstanceOf` x = True -- y `isInstanceOf` x = True
− src/Test/Speculate/Expr/TypeInfo.hs
@@ -1,255 +0,0 @@-{-# Language DeriveDataTypeable, StandaloneDeriving #-} -- for GHC <= 7.8--- |--- Module : Test.Speculate.Expr.TypeInfo--- Copyright : (c) 2016-2017 Rudy Matela--- License : 3-Clause BSD (see the file LICENSE)--- Maintainer : Rudy Matela <rudy@matela.com.br>------ This module is part of Speculate.------ Typeclass instance information.-module Test.Speculate.Expr.TypeInfo- ( Instances- , Instance (..)- , TypeRep-- -- * Smart constructors- , ins- , eq, eqWith- , ord, ordWith- , eqOrd- , listable, listableWith-- -- * Queries on Instances- , instanceType- , findInfo- , names- , eqE, isEq, isEqE- , leE, ltE, isOrd, isOrdE- , isEqOrd, isEqOrdE- , tiersE, isListable-- -- * Type info for standard Haskell types- , preludeInstances-- -- * Does not belong here?- , defNames-- , boolTy- , mkEqnTy- )-where--import Test.Speculate.Expr.Core-import Test.Speculate.Expr.Match-import Test.Speculate.Utils hiding (ord)-import Test.LeanCheck-import Test.LeanCheck.Utils hiding (comparison)-import Test.LeanCheck.Error (errorToFalse)-import Data.Dynamic--import Data.Maybe (isJust,fromMaybe,listToMaybe,catMaybes,mapMaybe)-import Data.List (find,(\\))----- | Type information needed to Speculate expressions (single type / single class).-data Instance = Eq TypeRep Expr- | Ord TypeRep Expr Expr- | Listable TypeRep [[Expr]]- | Names TypeRep [String]---- | Type information needed to Speculate expressions.-type Instances = [Instance]--instanceType :: Instance -> TypeRep-instanceType (Eq t _) = t-instanceType (Ord t _ _) = t-instanceType (Listable t _) = t-instanceType (Names t _) = t---- | Usage: @ins1 "x" (undefined :: Type)@-ins1 :: (Typeable a, Listable a, Show a, Eq a, Ord a)- => String -> a -> Instances-ins1 n x = eq x ++ ord x ++ listable x ++ name n x--ins :: (Typeable a, Listable a, Show a, Eq a, Ord a)- => String -> a -> Instances-ins n x = concat- [ x / n-- , [x] / n ++ "s"- , [[x]] / n ++ "ss"---, [[[x]]] / n ++ "ss"-- , (x,x) / n ++ m- , (x,x,x) / n ++ m ++ o---, (x,x,x,x) / n ++ m ++ o ++ p-- , [(x,x)] / n ++ m ++ "s"---, [(x,x,x)] / n ++ m ++ o ++ "ss"----, (x,[x]) / n ++ m ++ "s"---, ([x],x) / n ++ "s" ++ m---, ([x],[x]) / n ++ "s" ++ m ++ "s"---, (x,(x,x)) / n ++ m ++ o---, ((x,x),x) / n ++ m ++ o-- , mayb x / "m" ++ n ++ "1"---, eith x x / "e" ++ n ++ o ++ "1"- ]- where- (/) :: (Typeable a, Listable a, Show a, Eq a, Ord a)- => a -> String -> Instances -- monomorphism restriction strikes again- (/) = flip ins1- infixr 0 /- m = namesFromTemplate n !! 1- o = namesFromTemplate m !! 1- p = namesFromTemplate o !! 1--- NOTE: the function typeInfoN is not perfect: it won't help produce types--- combining different sub-types, like for example: (Bool,Int). But it is--- way better than the original version in which I had to explictly define--- everything. A definitive solution is still to be thought of.--- NOTE: see related TODO on the definition of basicInstances--eq :: (Typeable a, Eq a) => a -> Instances-eq x = eqWith $ (==) -:> x--ord :: (Typeable a, Ord a) => a -> Instances-ord x = ordWith $ (<=) -:> x--eqOrd :: (Typeable a, Eq a, Ord a) => a -> Instances-eqOrd x = eq x ++ ord x--listable :: (Typeable a, Show a, Listable a) => a -> Instances-listable x = listableWith $ tiers `asTypeOf` [[x]]--name :: Typeable a => String -> a -> Instances-name n x = [Names (typeOf x) (namesFromTemplate n)]--eqWith :: (Typeable a, Eq a) => (a -> a -> Bool) -> Instances-eqWith (==) = [Eq (typeOf $ arg (==)) $ constant "==" $ errorToFalse .: (==)]- where- arg :: (a -> b) -> a- arg _ = undefined--ordWith :: (Typeable a, Ord a) => (a -> a -> Bool) -> Instances-ordWith (<=) = [Ord (typeOf $ arg (<=))- (constant "<=" (errorToFalse .: (<=)))- (constant "<" ((errorToFalse . not) .: flip (<=)))]- where- arg :: (a -> b) -> a- arg _ = undefined--listableWith :: (Typeable a, Show a) => [[a]] -> Instances-listableWith xss =- [Listable (typeOf $ head $ head xss) (mapT showConstant xss)]--isEq :: Instances -> TypeRep -> Bool-isEq ti = isJust . eqE ti--isOrd :: Instances -> TypeRep -> Bool-isOrd ti = isJust . ltE ti--isEqOrd :: Instances -> TypeRep -> Bool-isEqOrd ti t = isOrd ti t && isEq ti t--isEqE :: Instances -> Expr -> Bool-isEqE ti = isEq ti . typ--isOrdE :: Instances -> Expr -> Bool-isOrdE ti = isOrd ti . typ--isEqOrdE :: Instances -> Expr -> Bool-isEqOrdE ti = isEqOrd ti . typ--isListable :: Instances -> TypeRep -> Bool-isListable ti t = isJust $ findInfo m ti- where- m (Listable t' ts) | t' == t = Just ts- m _ = Nothing---- TODO: implement above using something similar to the following--- isComparable ti = isJust . (`findInfo` ti) . typ--findInfo :: (Instance -> Maybe a) -> Instances -> Maybe a-findInfo may = listToMaybe . mapMaybe may--findInfoOr :: a -> (Instance -> Maybe a) -> Instances -> a-findInfoOr def may = fromMaybe def . findInfo may--names :: Instances -> TypeRep -> [String]-names ti t = findInfoOr defNames m ti- where- m (Names t' ns) | t == t' = Just ns- m _ = Nothing--tiersE :: Instances -> TypeRep -> [[Expr]]-tiersE ti t = findInfoOr (error $ "could not find Listable " ++ show t) m ti- where- m (Listable t' ts) | t == t' = Just ts- m _ = Nothing--eqE :: Instances -> TypeRep -> Maybe Expr-eqE ti t = findInfo m ti- where- m (Eq t' eq) | t == t' = Just eq- m _ = Nothing--ltE :: Instances -> TypeRep -> Maybe Expr-ltE ti t = findInfo m ti- where- m (Ord t' _ lt) | t == t' = Just lt- m _ = Nothing--leE :: Instances -> TypeRep -> Maybe Expr-leE ti t = findInfo m ti- where- m (Ord t' le _) | t == t' = Just le- m _ = Nothing--deriving instance Typeable Word2 -- for GHC <= 7.8---- TODO: include *ALL* prelude types on basicInstances-preludeInstances :: Instances-preludeInstances = concat- [ ins1 "x" (undefined :: ())- , ins1 "xs" (undefined :: [()])-- , ins "p" (undefined :: Bool)-- , ins "x" (undefined :: Int)---, ins "x" (undefined :: Word)- , ins "x" (undefined :: Integer)-- , ins "o" (undefined :: Ordering)- , ins "c" (undefined :: Char)-- , ins "q" (undefined :: Rational)- , ins "f" (undefined :: Float)- , ins "f" (undefined :: Double)---- TODO: uncomment the following and investigate why compilation takes so long---, ins "x" (undefined :: Int1)---, ins "x" (undefined :: Int2)---, ins "x" (undefined :: Int3)---, ins "x" (undefined :: Int4)---, ins "x" (undefined :: Word1)- , ins "x" (undefined :: Word2)---, ins "x" (undefined :: Word3)---, ins "x" (undefined :: Word4)---, ins "x" (undefined :: Nat1)---, ins "x" (undefined :: Nat2)---, ins "x" (undefined :: Nat3)---, ins "x" (undefined :: Nat4)---, ins "x" (undefined :: Nat5)---, ins "x" (undefined :: Nat6)---, ins "x" (undefined :: Nat7)- ]--- WHOA! Have I discovered a "bug" in GHC? adding to many type compositions--- on ins and types on preludeInstances makes compilation of this module--- *really* slow: it takes a whopping 2 minutes!--- (the above report is using -O2, I have not tested without optimizations).---defNames :: [String]-defNames = namesFromTemplate "x"
src/Test/Speculate/Utils/Typeable.hs view
@@ -67,7 +67,7 @@ unFunTy :: TypeRep -> (TypeRep,TypeRep) unFunTy t | isFunTy t = let (f,[a,b]) = splitTyConApp t in (a,b)- | otherwise = error "unFunTy: not a function type"+ | otherwise = error $ "error (unFunTy): `" ++ show t ++ "` is not a function type" argumentTy :: TypeRep -> TypeRep argumentTy = fst . unFunTy
tests/Test.hs view
@@ -49,6 +49,7 @@ , ii, jj, kk, ii' , negate' , ff, gg+ , ff2, hh2, hh3, hh4, hh5, hh6, hh7 , succ' , idE@@ -67,10 +68,13 @@ , odd', even' -- ** Characters- , aa+ , aa, bb+ , space, lineBreak , cc, dd , ord' , ordE+ , emptyString+ , ccs -- ** Lists (of Inteters) , ll@@ -350,7 +354,39 @@ gg :: Expr -> Expr gg = (ggE :$) where ggE = constant "g" (undefined :: Int -> Int) +ff2 :: Expr -> Expr -> Expr+ff2 e1 e2 = ffE :$ e1 :$ e2+ where ffE = constant "f" (undefined :: Int -> Int -> Int) +hh2 :: Expr -> Expr -> Expr+hh2 e1 e2 = hhE :$ e1 :$ e2+ where hhE = constant "h" (undefined :: Int -> Int -> Int)++hh3 :: Expr -> Expr -> Expr -> Expr+hh3 e1 e2 e3 = hhE :$ e1 :$ e2 :$ e3+ where hhE = constant "h" (undefined :: Int -> Int -> Int -> Int)++hh4 :: Expr -> Expr -> Expr -> Expr -> Expr+hh4 e1 e2 e3 e4 = hhE :$ e1 :$ e2 :$ e3 :$ e4+ where hhE = constant "h" (undefined :: Int -> Int -> Int -> Int -> Int)++hh5 :: Expr -> Expr -> Expr -> Expr -> Expr -> Expr+hh5 e1 e2 e3 e4 e5 = hhE :$ e1 :$ e2 :$ e3 :$ e4 :$ e5+ where hhE = constant "h" (undefined :: Int -> Int -> Int -> Int -> Int -> Int)++hh6 :: Expr -> Expr -> Expr -> Expr -> Expr -> Expr -> Expr+hh6 e1 e2 e3 e4 e5 e6 = hhE :$ e1 :$ e2 :$ e3 :$ e4 :$ e5 :$ e6+ where hhE = constant "h" (undefined :: Int -> Int -> Int -> Int -> Int -> Int -> Int)++hh7 :: Expr -> Expr -> Expr -> Expr -> Expr -> Expr -> Expr -> Expr+hh7 e1 e2 e3 e4 e5 e6 e7 = hhE :$ e1 :$ e2 :$ e3 :$ e4 :$ e5 :$ e6 :$ e7+ where hhE = constant "h" (undefined :: Int -> Int -> Int -> Int -> Int -> Int -> Int -> Int)++-- unification (hh5 yy zz (ff2 ii ii) (ff2 jj jj) kk) (hh5 (ff2 xx xx) (ff2 yy yy) jj kk zz)++-- unification (hh7 yy zz xx' (ff2 ii ii) (ff2 jj jj) (ff2 kk kk) ii')+-- (hh7 (ff2 xx xx) (ff2 yy yy) (ff2 zz zz) jj kk ii' xx')+ true :: Expr true = showConstant (True :: Bool) @@ -406,9 +442,18 @@ even' = (evenE :$) where evenE = constant "even" (even :: Int -> Bool) -aa :: Expr -- a, the character, not variable+aa :: Expr -- a, the character, not a variable aa = showConstant 'a' +bb :: Expr -- bee, the character, not a variable+bb = showConstant 'b'++space :: Expr -- space, the character+space = showConstant ' '++lineBreak :: Expr -- lineBreak, the character+lineBreak = showConstant '\n'+ cc :: Expr -- cee, a variable character cc = var "c" char @@ -421,7 +466,13 @@ ordE :: Expr ordE = constant "ord" Data.Char.ord +emptyString :: Expr+emptyString = showConstant "" +ccs :: Expr -- cees+ccs = var "cs" [char]++ ll :: Expr ll = showConstant ([] :: [Int]) @@ -432,7 +483,11 @@ yys = var "ys" [int] (-:-) :: Expr -> Expr -> Expr-e1 -:- e2 = consE :$ e1 :$ e2+e1 -:- e2+ | typ e1 == typeOf (undefined :: Int) = consE :$ e1 :$ e2+ | typ e1 == typeOf (undefined :: Char) = stringConsE :$ e1 :$ e2+ where+ stringConsE = constant ":" ((:) :: Char -> String -> String) infixr 5 -:- consE :: Expr@@ -460,8 +515,9 @@ sort' :: Expr -> Expr sort' exs = sortE :$ exs where sortE = constant "sort" (sort :: [Int] -> [Int]) --- boolTy already exported by Speculate.TypeInfo +-- boolTy already exported by Speculate.Instance+ intTy :: TypeRep intTy = typeOf int @@ -647,3 +703,5 @@ -- TODO: maybe use expressionsT as the main function to generate Exprs. -- By using it, I speculate a 20% increase in runtime. But the code will -- certainly be smaller and easier to maintain.++instance Listable Instance where list = preludeInstances
tests/test-expr.hs view
@@ -16,7 +16,6 @@ -- for Travis: deriving instance Typeable Thyght deriving instance Typeable Equation-deriving instance Typeable Expr main :: IO () main = mainTest tests 10000@@ -41,6 +40,7 @@ , holds n $ okEqOrd -:> expr+ , holds n $ okEqOrd -:> (undefined :: Instance) , holds n $ compare ==== compareComplexity , holds n $ LC.comparison lexicompare , holds n $ LC.comparison compareComplexity@@ -100,22 +100,6 @@ , renameBy (\(c:cs) -> succ c:cs) ((xx -+- yy) -+- ord' cc) == ((yy -+- zz) -+- ord' dd) - , unification xx yy == Just [("y",xx),("x",yy)]- , (canonicalize <$> unify xx yy) == Just xx- , unification zero zero == Just []- , unification zero one == Nothing- , unification xx one == Just [("x",one)]- , unification (zero -+- xx) (zero -+- one) == Just [("x",one)]- , unification (zero -+- xx) (yy -+- one) == Just [("x",one),("y",zero)]- , unify (zero -+- xx) (yy -+- one) == Just (zero -+- one)- , unification (ff xx) (ff (gg yy)) == Just [("x",gg yy)]- , unification (ff xx -+- xx) (yy -+- zero) == Just [("x",zero),("y",ff xx)]- , unify (ff xx -+- xx) (yy -+- zero) == Just (ff zero -+- zero)- , unification (ff xx) (gg yy) == Nothing- , unification (ff xx) (ff yy) == unification xx yy- , (canonicalize <$> unify (negate' (negate' xx) -+- yy) (xx -+- zero))- == Just (negate' (negate' xx) -+- zero)- , canonicalize (xx -+- yy) == (xx -+- yy) , canonicalize (jj -+- (ii -+- ii))@@ -209,4 +193,15 @@ #endif , holds n $ \e1 e2 -> e1 `isSub` e2 == (e1 `elem` subexprsV e2)++ , show (emptyString) == "\"\" :: [Char]"+ , show (space -:- emptyString) == "\" \" :: [Char]"+ , show (space -:- ccs) == "' ':cs :: [Char]"+ , show (aa -:- bb -:- emptyString) == "\"ab\" :: [Char]"+ , show (aa -:- bb -:- ccs) == "'a':'b':cs :: [Char]"+ , show (aa -:- space -:- bb -:- lineBreak -:- emptyString) == "\"a b\\n\" :: [Char]"+ , show (cc -:- space -:- dd -:- lineBreak -:- emptyString) == "c:' ':d:\"\\n\" :: [Char]"+ , show (cc -:- space -:- dd -:- lineBreak -:- ccs) == "c:' ':d:'\\n':cs :: [Char]"+ , show (cc -:- aa -:- bb -:- emptyString) == "c:\"ab\" :: [Char]"+ , show (cc -:- aa -:- bb -:- space -:- aa -:- bb -:- emptyString) == "c:\"ab ab\" :: [Char]" ]