module Data.Express.Canon
( canonicalize
, canonicalizeWith
, canonicalization
, canonicalizationWith
, isCanonical
, isCanonicalWith
, canonicalVariations
, mostGeneralCanonicalVariation
, mostSpecificCanonicalVariation
, fastCanonicalVariations
, fastMostGeneralVariation
, fastMostSpecificVariation
)
where
import Data.Express.Basic
import Data.Express.Name
import Data.Express.Instances
import Data.List ((\\))
canonicalizeWith :: (Expr -> [String]) -> Expr -> Expr
canonicalizeWith :: (Expr -> [String]) -> Expr -> Expr
canonicalizeWith Expr -> [String]
namesFor Expr
e = Expr
e Expr -> [(Expr, Expr)] -> Expr
//- (Expr -> [String]) -> Expr -> [(Expr, Expr)]
canonicalizationWith Expr -> [String]
namesFor Expr
e
canonicalizationWith :: (Expr -> [String]) -> Expr -> [(Expr,Expr)]
canonicalizationWith :: (Expr -> [String]) -> Expr -> [(Expr, Expr)]
canonicalizationWith Expr -> [String]
namesFor Expr
e = [Expr] -> [(Expr, Expr)] -> [(Expr, Expr)]
cr (Expr -> [Expr]
vars Expr
e) []
where
cr :: [Expr] -> [(Expr,Expr)] -> [(Expr,Expr)]
cr :: [Expr] -> [(Expr, Expr)] -> [(Expr, Expr)]
cr [] [(Expr, Expr)]
bs = [(Expr, Expr)]
bs
cr (Expr
e:[Expr]
es) [(Expr, Expr)]
bs = [Expr] -> [(Expr, Expr)] -> [(Expr, Expr)]
cr [Expr]
es
([(Expr, Expr)] -> [(Expr, Expr)])
-> [(Expr, Expr)] -> [(Expr, Expr)]
forall a b. (a -> b) -> a -> b
$ if Expr
e Expr -> [Expr] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` ((Expr, Expr) -> Expr) -> [(Expr, Expr)] -> [Expr]
forall a b. (a -> b) -> [a] -> [b]
map (Expr, Expr) -> Expr
forall a b. (a, b) -> a
fst [(Expr, Expr)]
bs
then [(Expr, Expr)]
bs
else (Expr
e, String
n String -> Expr -> Expr
`varAsTypeOf` Expr
e)(Expr, Expr) -> [(Expr, Expr)] -> [(Expr, Expr)]
forall a. a -> [a] -> [a]
:[(Expr, Expr)]
bs
where
existingNames :: [String]
existingNames = [String
n | (Expr
_,Value (Char
'_':String
n) Dynamic
_) <- [(Expr, Expr)]
bs]
freshNames :: [String]
freshNames = Expr -> [String]
namesFor Expr
e [String] -> [String] -> [String]
forall a. Eq a => [a] -> [a] -> [a]
\\ [String]
existingNames
n :: String
n = [String] -> String
forall a. [a] -> a
head [String]
freshNames
isCanonicalWith :: (Expr -> [String]) -> Expr -> Bool
isCanonicalWith :: (Expr -> [String]) -> Expr -> Bool
isCanonicalWith Expr -> [String]
ti Expr
e = (Expr -> [String]) -> Expr -> Expr
canonicalizeWith Expr -> [String]
ti Expr
e Expr -> Expr -> Bool
forall a. Eq a => a -> a -> Bool
== Expr
e
canonicalize :: Expr -> Expr
canonicalize :: Expr -> Expr
canonicalize = (Expr -> [String]) -> Expr -> Expr
canonicalizeWith Expr -> [String]
names'
canonicalization :: Expr -> [(Expr,Expr)]
canonicalization :: Expr -> [(Expr, Expr)]
canonicalization = (Expr -> [String]) -> Expr -> [(Expr, Expr)]
canonicalizationWith Expr -> [String]
names'
isCanonical :: Expr -> Bool
isCanonical :: Expr -> Bool
isCanonical = (Expr -> [String]) -> Expr -> Bool
isCanonicalWith Expr -> [String]
names'
names' :: Expr -> [String]
names' :: Expr -> [String]
names' = [Expr] -> Expr -> [String]
lookupNames [Expr]
preludeNameInstances
canonicalVariations :: Expr -> [Expr]
canonicalVariations :: Expr -> [Expr]
canonicalVariations Expr
e = (Expr -> Expr) -> [Expr] -> [Expr]
forall a b. (a -> b) -> [a] -> [b]
map ([Expr] -> Expr -> Expr
canonicalizeKeeping (Expr -> [Expr]
nonHoleVars Expr
e))
([Expr] -> [Expr]) -> [Expr] -> [Expr]
forall a b. (a -> b) -> a -> b
$ Expr -> [Expr]
fastCanonicalVariations Expr
e
mostGeneralCanonicalVariation :: Expr -> Expr
mostGeneralCanonicalVariation :: Expr -> Expr
mostGeneralCanonicalVariation Expr
e = [Expr] -> Expr -> Expr
canonicalizeKeeping (Expr -> [Expr]
nonHoleVars Expr
e)
(Expr -> Expr) -> Expr -> Expr
forall a b. (a -> b) -> a -> b
$ Expr -> Expr
fastMostGeneralVariation Expr
e
mostSpecificCanonicalVariation :: Expr -> Expr
mostSpecificCanonicalVariation :: Expr -> Expr
mostSpecificCanonicalVariation Expr
e = [Expr] -> Expr -> Expr
canonicalizeKeeping (Expr -> [Expr]
nonHoleVars Expr
e)
(Expr -> Expr) -> Expr -> Expr
forall a b. (a -> b) -> a -> b
$ Expr -> Expr
fastMostSpecificVariation Expr
e
fastCanonicalVariations :: Expr -> [Expr]
fastCanonicalVariations :: Expr -> [Expr]
fastCanonicalVariations Expr
e
| [Expr] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Expr]
hs' = [Expr
e]
| Bool
otherwise = (Expr -> [Expr]) -> [Expr] -> [Expr]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap Expr -> [Expr]
fastCanonicalVariations
([Expr] -> [Expr]) -> ([Expr] -> [Expr]) -> [Expr] -> [Expr]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ([Expr] -> Expr) -> [[Expr]] -> [Expr]
forall a b. (a -> b) -> [a] -> [b]
map (Expr -> [Expr] -> Expr
fill Expr
e) ([[Expr]] -> [Expr]) -> ([Expr] -> [[Expr]]) -> [Expr] -> [Expr]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> [Expr] -> [[Expr]]
fillings Int
0
([Expr] -> [Expr]) -> [Expr] -> [Expr]
forall a b. (a -> b) -> a -> b
$ [Expr
h | Expr
h <- [Expr]
hs', Expr -> TypeRep
typ Expr
h TypeRep -> TypeRep -> Bool
forall a. Eq a => a -> a -> Bool
== Expr -> TypeRep
typ Expr
h']
where
hs' :: [Expr]
hs' = Expr -> [Expr]
holes Expr
e
h' :: Expr
h' = [Expr] -> Expr
forall a. [a] -> a
head [Expr]
hs'
names :: [String]
names = String -> [String]
variableNamesFromTemplate String
"x" [String] -> [String] -> [String]
forall a. Eq a => [a] -> [a] -> [a]
\\ Expr -> [String]
varnames Expr
e
fillings :: Int -> [Expr] -> [[Expr]]
fillings :: Int -> [Expr] -> [[Expr]]
fillings Int
i [] = [[]]
fillings Int
i (Expr
h:[Expr]
hs) =
[[[Expr]]] -> [[Expr]]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat ([[[Expr]]] -> [[Expr]]) -> [[[Expr]]] -> [[Expr]]
forall a b. (a -> b) -> a -> b
$ ([Expr] -> [Expr]) -> [[Expr]] -> [[Expr]]
forall a b. (a -> b) -> [a] -> [b]
map ([String]
names [String] -> Int -> String
forall a. [a] -> Int -> a
!! Int
i String -> Expr -> Expr
`varAsTypeOf` Expr
hExpr -> [Expr] -> [Expr]
forall a. a -> [a] -> [a]
:) (Int -> [Expr] -> [[Expr]]
fillings (Int
iInt -> Int -> Int
forall a. Num a => a -> a -> a
+Int
1) [Expr]
hs)
[[Expr]] -> [[[Expr]]] -> [[[Expr]]]
forall a. a -> [a] -> [a]
: [ ([Expr] -> [Expr]) -> [[Expr]] -> [[Expr]]
forall a b. (a -> b) -> [a] -> [b]
map (String
n String -> Expr -> Expr
`varAsTypeOf` Expr
hExpr -> [Expr] -> [Expr]
forall a. a -> [a] -> [a]
:) (Int -> [Expr] -> [[Expr]]
fillings Int
i [Expr]
hs)
| String
n <- Int -> [String] -> [String]
forall a. Int -> [a] -> [a]
take Int
i [String]
names ]
fastMostGeneralVariation :: Expr -> Expr
fastMostGeneralVariation :: Expr -> Expr
fastMostGeneralVariation Expr
e = Expr -> [Expr] -> Expr
fill Expr
e ((String -> Expr -> Expr) -> [String] -> [Expr] -> [Expr]
forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith String -> Expr -> Expr
varAsTypeOf [String]
names (Expr -> [Expr]
holes Expr
e))
where
names :: [String]
names = String -> [String]
variableNamesFromTemplate String
"x" [String] -> [String] -> [String]
forall a. Eq a => [a] -> [a] -> [a]
\\ Expr -> [String]
varnames Expr
e
fastMostSpecificVariation :: Expr -> Expr
fastMostSpecificVariation :: Expr -> Expr
fastMostSpecificVariation Expr
e = Expr -> [Expr] -> Expr
fill Expr
e ((Expr -> Expr) -> [Expr] -> [Expr]
forall a b. (a -> b) -> [a] -> [b]
map (String
name String -> Expr -> Expr
`varAsTypeOf`) (Expr -> [Expr]
holes Expr
e))
where
name :: String
name = [String] -> String
forall a. [a] -> a
head ([String] -> String) -> [String] -> String
forall a b. (a -> b) -> a -> b
$ String -> [String]
variableNamesFromTemplate String
"x" [String] -> [String] -> [String]
forall a. Eq a => [a] -> [a] -> [a]
\\ Expr -> [String]
varnames Expr
e
varnames :: Expr -> [String]
varnames :: Expr -> [String]
varnames Expr
e = [String
n | Value (Char
'_':String
n) Dynamic
_ <- Expr -> [Expr]
vars Expr
e]
nonHoleVars :: Expr -> [Expr]
nonHoleVars :: Expr -> [Expr]
nonHoleVars = (Expr -> Bool) -> [Expr] -> [Expr]
forall a. (a -> Bool) -> [a] -> [a]
filter (Bool -> Bool
not (Bool -> Bool) -> (Expr -> Bool) -> Expr -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Expr -> Bool
isHole) ([Expr] -> [Expr]) -> (Expr -> [Expr]) -> Expr -> [Expr]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Expr -> [Expr]
nubVars
canonicalizeKeeping :: [Expr] -> Expr -> Expr
canonicalizeKeeping :: [Expr] -> Expr -> Expr
canonicalizeKeeping [Expr]
vs Expr
e = (Expr -> [String]) -> Expr -> Expr
canonicalizeWith Expr -> [String]
namesFor Expr
e
where
nm :: Expr -> String
nm (Value (Char
'_':String
n) Dynamic
_) = String
n
namesFor :: Expr -> [String]
namesFor Expr
v | Expr
v Expr -> [Expr] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Expr]
vs = Expr -> String
nm Expr
v String -> [String] -> [String]
forall a. a -> [a] -> [a]
: [String]
forall a. a
err
| Bool
otherwise = Expr -> [String]
names' Expr
v [String] -> [String] -> [String]
forall a. Eq a => [a] -> [a] -> [a]
\\ (Expr -> String) -> [Expr] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map Expr -> String
nm [Expr]
vs
err :: a
err = String -> a
forall a. HasCallStack => String -> a
error String
"Data.Express.canonicalizeKeeping: the impossible happened. This is definitely a bug."