module Test.Speculate.Expr.Core
( module Data.Express
, module Data.Express.Utils.Typeable
, compareLexicographicallyBy
, compareComplexityThenIndex
, isConstantNamed
, unrepeatedVars
, isAssignment
, Binds
, unify
, unification
, isCanonInstanceOf
, hasCanonInstanceOf
)
where
import Data.Express
import Data.Express.Utils.Typeable
import Test.Speculate.Utils
import Data.Monoid ((<>))
import Data.Functor ((<$>))
compareLexicographicallyBy :: (Expr -> Expr -> Ordering) -> Expr -> Expr -> Ordering
compareLexicographicallyBy :: (Expr -> Expr -> Ordering) -> Expr -> Expr -> Ordering
compareLexicographicallyBy Expr -> Expr -> Ordering
compareConstants = Expr -> Expr -> Ordering
cmp
where
(Expr
f :$ Expr
x) cmp :: Expr -> Expr -> Ordering
`cmp` (Expr
g :$ Expr
y) = Expr
f Expr -> Expr -> Ordering
`cmp` Expr
g Ordering -> Ordering -> Ordering
forall a. Semigroup a => a -> a -> a
<> Expr
x Expr -> Expr -> Ordering
`cmp` Expr
y
(Expr
_ :$ Expr
_) `cmp` Expr
_ = Ordering
GT
Expr
_ `cmp` (Expr
_ :$ Expr
_) = Ordering
LT
Expr
e1 `cmp` Expr
e2 = case (Expr -> Bool
isVar Expr
e1, Expr -> Bool
isVar Expr
e2) of
(Bool
True, Bool
True) -> let Value String
n1 Dynamic
_ = Expr
e1
Value String
n2 Dynamic
_ = Expr
e2
in Expr -> TypeRep
typ Expr
e1 TypeRep -> TypeRep -> Ordering
`compareTy` Expr -> TypeRep
typ Expr
e2
Ordering -> Ordering -> Ordering
forall a. Semigroup a => a -> a -> a
<> String -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length String
n1 Int -> Int -> Ordering
forall a. Ord a => a -> a -> Ordering
`compare` String -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length String
n2
Ordering -> Ordering -> Ordering
forall a. Semigroup a => a -> a -> a
<> String
n1 String -> String -> Ordering
forall a. Ord a => a -> a -> Ordering
`compare` String
n2
(Bool
False, Bool
True) -> Ordering
GT
(Bool
True, Bool
False) -> Ordering
LT
(Bool
False, Bool
False) -> Expr
e1 Expr -> Expr -> Ordering
`compareConstants` Expr
e2
compareComplexityThenIndex :: [Expr] -> Expr -> Expr -> Ordering
compareComplexityThenIndex :: [Expr] -> Expr -> Expr -> Ordering
compareComplexityThenIndex [Expr]
as = Expr -> Expr -> Ordering
compareComplexity (Expr -> Expr -> Ordering)
-> (Expr -> Expr -> Ordering) -> Expr -> Expr -> Ordering
forall a. Semigroup a => a -> a -> a
<> (Expr -> Expr -> Ordering) -> Expr -> Expr -> Ordering
compareLexicographicallyBy Expr -> Expr -> Ordering
cmp
where
Expr
e1 cmp :: Expr -> Expr -> Ordering
`cmp` Expr
e2 | Expr -> Int
arity Expr
e1 Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0 Bool -> Bool -> Bool
&& Expr -> Int
arity Expr
e2 Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
/= Int
0 = Ordering
LT
Expr
e1 `cmp` Expr
e2 | Expr -> Int
arity Expr
e1 Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
/= Int
0 Bool -> Bool -> Bool
&& Expr -> Int
arity Expr
e2 Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0 = Ordering
GT
Expr
e1 `cmp` Expr
e2 = [Expr] -> Expr -> Expr -> Ordering
forall a. Eq a => [a] -> a -> a -> Ordering
compareIndex [Expr]
as Expr
e1 Expr
e2 Ordering -> Ordering -> Ordering
forall a. Semigroup a => a -> a -> a
<> Expr
e1 Expr -> Expr -> Ordering
forall a. Ord a => a -> a -> Ordering
`compare` Expr
e2
countVars :: Expr -> [(Expr,Int)]
countVars :: Expr -> [(Expr, Int)]
countVars Expr
e = (Expr -> (Expr, Int)) -> [Expr] -> [(Expr, Int)]
forall a b. (a -> b) -> [a] -> [b]
map (\Expr
e' -> (Expr
e',[Expr] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length ([Expr] -> Int) -> ([Expr] -> [Expr]) -> [Expr] -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Expr -> Bool) -> [Expr] -> [Expr]
forall a. (a -> Bool) -> [a] -> [a]
filter (Expr -> Expr -> Bool
forall a. Eq a => a -> a -> Bool
== Expr
e') ([Expr] -> Int) -> [Expr] -> Int
forall a b. (a -> b) -> a -> b
$ Expr -> [Expr]
vars Expr
e)) ([Expr] -> [(Expr, Int)]) -> [Expr] -> [(Expr, Int)]
forall a b. (a -> b) -> a -> b
$ Expr -> [Expr]
nubVars Expr
e
unrepeatedVars :: Expr -> Bool
unrepeatedVars :: Expr -> Bool
unrepeatedVars = ((Expr, Int) -> Bool) -> [(Expr, Int)] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (\(Expr
_,Int
n) -> Int
n Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
1) ([(Expr, Int)] -> Bool) -> (Expr -> [(Expr, Int)]) -> Expr -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Expr -> [(Expr, Int)]
countVars
isAssignment :: Expr -> Bool
isAssignment :: Expr -> Bool
isAssignment ((Value String
"==" Dynamic
_ :$ Expr
e1) :$ Expr
e2) = Expr -> Bool
isVar Expr
e1 Bool -> Bool -> Bool
|| Expr -> Bool
isVar Expr
e2
isAssignment Expr
_ = Bool
False
isConstantNamed :: Expr -> String -> Bool
e :: Expr
e@(Value String
n' Dynamic
_) isConstantNamed :: Expr -> String -> Bool
`isConstantNamed` String
n = Expr -> Bool
isConst Expr
e Bool -> Bool -> Bool
&& String
n' String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== String
n
Expr
_ `isConstantNamed` String
_ = Bool
False
type Binds = [(Expr,Expr)]
unify :: Expr -> Expr -> Maybe Expr
unify :: Expr -> Expr -> Maybe Expr
unify Expr
e1 Expr
e2 = (Expr
e1 Expr -> [(Expr, Expr)] -> Expr
//-) ([(Expr, Expr)] -> Expr) -> Maybe [(Expr, Expr)] -> Maybe Expr
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Expr -> Expr -> Maybe [(Expr, Expr)]
unification Expr
e1 Expr
e2
unification :: Expr -> Expr -> Maybe [(Expr,Expr)]
unification :: Expr -> Expr -> Maybe [(Expr, Expr)]
unification = Expr -> Expr -> Maybe [(Expr, Expr)]
naiveUnification
findBind :: Expr -> Expr -> Either Bool (Expr,Expr)
findBind :: Expr -> Expr -> Either Bool (Expr, Expr)
findBind Expr
e1 Expr
e2 | Expr -> TypeRep
typ Expr
e1 TypeRep -> TypeRep -> Bool
forall a. Eq a => a -> a -> Bool
/= Expr -> TypeRep
typ Expr
e2 = Bool -> Either Bool (Expr, Expr)
forall a b. a -> Either a b
Left Bool
False
| Expr
e1 Expr -> Expr -> Bool
forall a. Eq a => a -> a -> Bool
== Expr
e2 = Bool -> Either Bool (Expr, Expr)
forall a b. a -> Either a b
Left Bool
True
| Expr -> Bool
isVar Expr
e1 = (Expr, Expr) -> Either Bool (Expr, Expr)
forall a b. b -> Either a b
Right (Expr
e1,Expr
e2)
| Expr -> Bool
isVar Expr
e2 = (Expr, Expr) -> Either Bool (Expr, Expr)
forall a b. b -> Either a b
Right (Expr
e2,Expr
e1)
findBind (Expr
f1 :$ Expr
x1) (Expr
f2 :$ Expr
x2) = case Expr -> Expr -> Either Bool (Expr, Expr)
findBind Expr
f1 Expr
f2 of
Left Bool
True -> Expr -> Expr -> Either Bool (Expr, Expr)
findBind Expr
x1 Expr
x2
Either Bool (Expr, Expr)
r -> Either Bool (Expr, Expr)
r
findBind Expr
e1 Expr
e2 = Bool -> Either Bool (Expr, Expr)
forall a b. a -> Either a b
Left (Expr
e1 Expr -> Expr -> Bool
forall a. Eq a => a -> a -> Bool
== Expr
e2)
naiveUnification :: Expr -> Expr -> Maybe [(Expr,Expr)]
naiveUnification :: Expr -> Expr -> Maybe [(Expr, Expr)]
naiveUnification Expr
e1' Expr
e2' = Expr -> Expr -> [(Expr, Expr)] -> Maybe [(Expr, Expr)]
uu Expr
e1' Expr
e2' []
where
uu :: Expr -> Expr -> Binds -> Maybe Binds
uu :: Expr -> Expr -> [(Expr, Expr)] -> Maybe [(Expr, Expr)]
uu Expr
e1' Expr
e2' [(Expr, Expr)]
bs' =
case Expr
-> Expr -> [(Expr, Expr)] -> Maybe (Expr, Expr, [(Expr, Expr)])
u Expr
e1' Expr
e2' [(Expr, Expr)]
bs' of
Maybe (Expr, Expr, [(Expr, Expr)])
Nothing -> Maybe [(Expr, Expr)]
forall a. Maybe a
Nothing
Just (Expr
e1,Expr
e2,[(Expr, Expr)]
bs) ->
if Expr
e1' Expr -> Expr -> Bool
forall a. Eq a => a -> a -> Bool
== Expr
e1 Bool -> Bool -> Bool
&& Expr
e2' Expr -> Expr -> Bool
forall a. Eq a => a -> a -> Bool
== Expr
e2
then [(Expr, Expr)] -> Maybe [(Expr, Expr)]
forall a. a -> Maybe a
Just [(Expr, Expr)]
bs
else Expr -> Expr -> [(Expr, Expr)] -> Maybe [(Expr, Expr)]
uu Expr
e1 Expr
e2 [(Expr, Expr)]
bs
u :: Expr -> Expr -> Binds -> Maybe (Expr,Expr,Binds)
u :: Expr
-> Expr -> [(Expr, Expr)] -> Maybe (Expr, Expr, [(Expr, Expr)])
u Expr
e1 Expr
e2 [(Expr, Expr)]
bs =
case Expr -> Expr -> Either Bool (Expr, Expr)
findBind Expr
e1 Expr
e2 of
Left Bool
False -> Maybe (Expr, Expr, [(Expr, Expr)])
forall a. Maybe a
Nothing
Left Bool
True -> (Expr, Expr, [(Expr, Expr)]) -> Maybe (Expr, Expr, [(Expr, Expr)])
forall a. a -> Maybe a
Just (Expr
e1,Expr
e2,[(Expr, Expr)]
bs)
Right (Expr
ex,Expr
e) ->
if Expr
ex Expr -> Expr -> Bool
`isSubexprOf` Expr
e
then Maybe (Expr, Expr, [(Expr, Expr)])
forall a. Maybe a
Nothing
else (Expr, Expr, [(Expr, Expr)]) -> Maybe (Expr, Expr, [(Expr, Expr)])
forall a. a -> Maybe a
Just ( Expr
e1 Expr -> [(Expr, Expr)] -> Expr
//- [(Expr
ex,Expr
e)]
, Expr
e2 Expr -> [(Expr, Expr)] -> Expr
//- [(Expr
ex,Expr
e)]
, (Expr
ex,Expr
e)(Expr, Expr) -> [(Expr, Expr)] -> [(Expr, Expr)]
forall a. a -> [a] -> [a]
:[(Expr
ex',Expr
e' Expr -> [(Expr, Expr)] -> Expr
//- [(Expr
ex,Expr
e)]) | (Expr
ex',Expr
e') <- [(Expr, Expr)]
bs]
)
isCanonInstanceOf :: Expr -> Expr -> Bool
Expr
e1 isCanonInstanceOf :: Expr -> Expr -> Bool
`isCanonInstanceOf` Expr
e2 =
case Expr
e1 Expr -> Expr -> Maybe [(Expr, Expr)]
`match` Expr
e2 of
Maybe [(Expr, Expr)]
Nothing -> Bool
False
Just [(Expr, Expr)]
xs -> ((Expr, Expr) -> Expr) -> [(Expr, Expr)] -> Bool
forall b a. Ord b => (a -> b) -> [a] -> Bool
strictlyOrderedOn (Expr, Expr) -> Expr
forall a b. (a, b) -> b
snd (((Expr, Expr) -> Expr) -> [(Expr, Expr)] -> [(Expr, Expr)]
forall b a. Ord b => (a -> b) -> [a] -> [a]
sortOn (Expr, Expr) -> Expr
forall a b. (a, b) -> a
fst [(Expr, Expr)]
xs)
hasCanonInstanceOf :: Expr -> Expr -> Bool
Expr
e1 hasCanonInstanceOf :: Expr -> Expr -> Bool
`hasCanonInstanceOf` Expr
e2 | Expr
e1 Expr -> Expr -> Bool
`isCanonInstanceOf` Expr
e2 = Bool
True
(Expr
e1f :$ Expr
e1x) `hasCanonInstanceOf` Expr
e2 | Expr
e1f Expr -> Expr -> Bool
`hasCanonInstanceOf` Expr
e2 Bool -> Bool -> Bool
||
Expr
e1x Expr -> Expr -> Bool
`hasCanonInstanceOf` Expr
e2 = Bool
True
Expr
_ `hasCanonInstanceOf` Expr
_ = Bool
False