Copyright | (c) 2021 Rudy Matela |
---|---|
License | 3-Clause BSD (see the file LICENSE) |
Maintainer | Rudy Matela <rudy@matela.com.br> |
Safe Haskell | Safe-Inferred |
Language | Haskell2010 |
This internal module reexports Express
along with a few other
utilities.
Synopsis
- module Data.Express
- (-...-) :: Expr -> Expr -> Expr -> Expr
- enumFromThenTo' :: Expr -> Expr -> Expr -> Expr
- (-...) :: Expr -> Expr -> Expr
- enumFromThen' :: Expr -> Expr -> Expr
- (-..-) :: Expr -> Expr -> Expr
- enumFromTo' :: Expr -> Expr -> Expr
- (-..) :: Expr -> Expr
- enumFrom' :: Expr -> Expr
- map' :: Expr -> Expr -> Expr
- mapE :: Expr
- (-.-) :: Expr -> Expr -> Expr
- compose :: Expr
- (-%-) :: Expr -> Expr -> Expr
- product' :: Expr -> Expr
- sum' :: Expr -> Expr
- or' :: Expr -> Expr
- and' :: Expr -> Expr
- qqs :: Expr
- pps :: Expr
- bs_ :: Expr
- sixtuple :: Expr -> Expr -> Expr -> Expr -> Expr -> Expr -> Expr
- quintuple :: Expr -> Expr -> Expr -> Expr -> Expr -> Expr
- quadruple :: Expr -> Expr -> Expr -> Expr -> Expr
- triple :: Expr -> Expr -> Expr -> Expr
- comma :: Expr
- pair :: Expr -> Expr -> Expr
- (-|-) :: Expr -> Expr -> Expr
- just :: Expr -> Expr
- justBool :: Expr
- justInt :: Expr
- nothingBool :: Expr
- nothingInt :: Expr
- nothing :: Expr
- compare' :: Expr -> Expr -> Expr
- caseOrdering :: Expr -> Expr -> Expr -> Expr -> Expr
- caseBool :: Expr -> Expr -> Expr -> Expr
- if' :: Expr -> Expr -> Expr -> Expr
- (-<-) :: Expr -> Expr -> Expr
- (-<=-) :: Expr -> Expr -> Expr
- (-/=-) :: Expr -> Expr -> Expr
- (-$-) :: Expr -> Expr -> Expr
- elem' :: Expr -> Expr -> Expr
- insert' :: Expr -> Expr -> Expr
- sort' :: Expr -> Expr
- init' :: Expr -> Expr
- length' :: Expr -> Expr
- null' :: Expr -> Expr
- tail' :: Expr -> Expr
- head' :: Expr -> Expr
- (-++-) :: Expr -> Expr -> Expr
- appendInt :: Expr
- (-:-) :: Expr -> Expr -> Expr
- unit :: Expr -> Expr
- consChar :: Expr
- consBool :: Expr
- consInt :: Expr
- cons :: Expr
- nilChar :: Expr
- nilBool :: Expr
- nilInt :: Expr
- emptyString :: Expr
- nil :: Expr
- zzs :: Expr
- yys :: Expr
- xxs :: Expr
- is_ :: Expr
- ordE :: Expr
- ord' :: Expr -> Expr
- lineBreak :: Expr
- space :: Expr
- zee :: Expr
- zed :: Expr
- dee :: Expr
- cee :: Expr
- bee :: Expr
- ae :: Expr
- ccs :: Expr
- dd :: Expr
- cc :: Expr
- cs_ :: Expr
- c_ :: Expr
- even' :: Expr -> Expr
- odd' :: Expr -> Expr
- signumE :: Expr
- signum' :: Expr -> Expr
- absE :: Expr
- abs' :: Expr -> Expr
- negateE :: Expr
- negate' :: Expr -> Expr
- const' :: Expr -> Expr -> Expr
- idString :: Expr
- idBools :: Expr
- idInts :: Expr
- idChar :: Expr
- idBool :: Expr
- idInt :: Expr
- idE :: Expr
- id' :: Expr -> Expr
- remE :: Expr
- rem' :: Expr -> Expr -> Expr
- quotE :: Expr
- quot' :: Expr -> Expr -> Expr
- modE :: Expr
- mod' :: Expr -> Expr -> Expr
- divE :: Expr
- div' :: Expr -> Expr -> Expr
- minus :: Expr
- times :: Expr
- (-*-) :: Expr -> Expr -> Expr
- plus :: Expr
- (-+-) :: Expr -> Expr -> Expr
- ooE :: Expr
- oo :: Expr -> Expr -> Expr
- question :: Expr
- (-?-) :: Expr -> Expr -> Expr
- hhE :: Expr
- hh :: Expr -> Expr
- ggE :: Expr
- gg :: Expr -> Expr
- ffE :: Expr
- ff :: Expr -> Expr
- minusTwo :: Expr
- minusOne :: Expr
- twelve :: Expr
- eleven :: Expr
- ten :: Expr
- nine :: Expr
- eight :: Expr
- seven :: Expr
- six :: Expr
- five :: Expr
- four :: Expr
- three :: Expr
- two :: Expr
- one :: Expr
- zero :: Expr
- nn :: Expr
- mm :: Expr
- ll :: Expr
- ii' :: Expr
- kk :: Expr
- jj :: Expr
- ii :: Expr
- xx' :: Expr
- zz :: Expr
- yy :: Expr
- xx :: Expr
- i_ :: Expr
- (-||-) :: Expr -> Expr -> Expr
- (-&&-) :: Expr -> Expr -> Expr
- not' :: Expr -> Expr
- implies :: Expr
- (-==>-) :: Expr -> Expr -> Expr
- orE :: Expr
- andE :: Expr
- notE :: Expr
- true :: Expr
- false :: Expr
- pp' :: Expr
- rr :: Expr
- qq :: Expr
- pp :: Expr
- b_ :: Expr
- fastMostSpecificVariation :: Expr -> Expr
- fastMostGeneralVariation :: Expr -> Expr
- fastCanonicalVariations :: Expr -> [Expr]
- mostSpecificCanonicalVariation :: Expr -> Expr
- mostGeneralCanonicalVariation :: Expr -> Expr
- canonicalVariations :: Expr -> [Expr]
- isCanonical :: Expr -> Bool
- canonicalization :: Expr -> [(Expr, Expr)]
- canonicalize :: Expr -> Expr
- isCanonicalWith :: (Expr -> [String]) -> Expr -> Bool
- canonicalizationWith :: (Expr -> [String]) -> Expr -> [(Expr, Expr)]
- canonicalizeWith :: (Expr -> [String]) -> Expr -> Expr
- preludeNameInstances :: [Expr]
- findValidApp :: [Expr] -> Expr -> Maybe Expr
- validApps :: [Expr] -> Expr -> [Expr]
- listVarsWith :: [Expr] -> Expr -> [Expr]
- lookupNames :: [Expr] -> Expr -> [String]
- lookupName :: [Expr] -> Expr -> String
- mkComparisonLE :: [Expr] -> Expr -> Expr -> Expr
- mkComparisonLT :: [Expr] -> Expr -> Expr -> Expr
- mkEquation :: [Expr] -> Expr -> Expr -> Expr
- mkComparison :: String -> [Expr] -> Expr -> Expr -> Expr
- isEqOrd :: [Expr] -> Expr -> Bool
- isOrd :: [Expr] -> Expr -> Bool
- isEq :: [Expr] -> Expr -> Bool
- isEqOrdT :: [Expr] -> TypeRep -> Bool
- isOrdT :: [Expr] -> TypeRep -> Bool
- isEqT :: [Expr] -> TypeRep -> Bool
- lookupComparison :: String -> TypeRep -> [Expr] -> Maybe Expr
- mkNameWith :: Typeable a => String -> a -> [Expr]
- mkName :: Typeable a => (a -> String) -> [Expr]
- mkOrdLessEqual :: Typeable a => (a -> a -> Bool) -> [Expr]
- mkOrd :: Typeable a => (a -> a -> Ordering) -> [Expr]
- mkEq :: Typeable a => (a -> a -> Bool) -> [Expr]
- reifyName :: (Typeable a, Name a) => a -> [Expr]
- reifyEqOrd :: (Typeable a, Ord a) => a -> [Expr]
- reifyOrd :: (Typeable a, Ord a) => a -> [Expr]
- reifyEq :: (Typeable a, Eq a) => a -> [Expr]
- deriveExpressCascading :: Name -> DecsQ
- deriveExpressIfNeeded :: Name -> DecsQ
- deriveExpress :: Name -> DecsQ
- class (Show a, Typeable a) => Express a where
- unfold :: Expr -> [Expr]
- fold :: [Expr] -> Expr
- unfoldTrio :: Expr -> (Expr, Expr, Expr)
- foldTrio :: (Expr, Expr, Expr) -> Expr
- unfoldPair :: Expr -> (Expr, Expr)
- foldPair :: (Expr, Expr) -> Expr
- foldApp :: [Expr] -> Expr
- fill :: Expr -> [Expr] -> Expr
- listVarsAsTypeOf :: String -> Expr -> [Expr]
- listVars :: Typeable a => String -> a -> [Expr]
- isComplete :: Expr -> Bool
- hasHole :: Expr -> Bool
- nubHoles :: Expr -> [Expr]
- holes :: Expr -> [Expr]
- isHole :: Expr -> Bool
- hole :: Typeable a => a -> Expr
- holeAsTypeOf :: Expr -> Expr
- varAsTypeOf :: String -> Expr -> Expr
- renameVarsBy :: (String -> String) -> Expr -> Expr
- (//) :: Expr -> [(Expr, Expr)] -> Expr
- (//-) :: Expr -> [(Expr, Expr)] -> Expr
- mapSubexprs :: (Expr -> Maybe Expr) -> Expr -> Expr
- mapConsts :: (Expr -> Expr) -> Expr -> Expr
- mapVars :: (Expr -> Expr) -> Expr -> Expr
- mapValues :: (Expr -> Expr) -> Expr -> Expr
- isSubexprOf :: Expr -> Expr -> Bool
- hasInstanceOf :: Expr -> Expr -> Bool
- encompasses :: Expr -> Expr -> Bool
- isInstanceOf :: Expr -> Expr -> Bool
- matchWith :: [(Expr, Expr)] -> Expr -> Expr -> Maybe [(Expr, Expr)]
- match :: Expr -> Expr -> Maybe [(Expr, Expr)]
- height :: Expr -> Int
- depth :: Expr -> Int
- size :: Expr -> Int
- arity :: Expr -> Int
- nubVars :: Expr -> [Expr]
- vars :: Expr -> [Expr]
- nubConsts :: Expr -> [Expr]
- consts :: Expr -> [Expr]
- nubValues :: Expr -> [Expr]
- values :: Expr -> [Expr]
- nubSubexprs :: Expr -> [Expr]
- subexprs :: Expr -> [Expr]
- isApp :: Expr -> Bool
- isValue :: Expr -> Bool
- isVar :: Expr -> Bool
- isConst :: Expr -> Bool
- isGround :: Expr -> Bool
- hasVar :: Expr -> Bool
- unfoldApp :: Expr -> [Expr]
- compareQuickly :: Expr -> Expr -> Ordering
- compareLexicographically :: Expr -> Expr -> Ordering
- compareComplexity :: Expr -> Expr -> Ordering
- showExpr :: Expr -> String
- showPrecExpr :: Int -> Expr -> String
- showOpExpr :: String -> Expr -> String
- toDynamic :: Expr -> Maybe Dynamic
- evl :: Typeable a => Expr -> a
- eval :: Typeable a => a -> Expr -> a
- evaluate :: Typeable a => Expr -> Maybe a
- isFun :: Expr -> Bool
- isWellTyped :: Expr -> Bool
- isIllTyped :: Expr -> Bool
- mtyp :: Expr -> Maybe TypeRep
- etyp :: Expr -> Either (TypeRep, TypeRep) TypeRep
- typ :: Expr -> TypeRep
- var :: Typeable a => String -> a -> Expr
- ($$) :: Expr -> Expr -> Maybe Expr
- val :: (Typeable a, Show a) => a -> Expr
- value :: Typeable a => String -> a -> Expr
- data Expr
- deriveNameCascading :: Name -> DecsQ
- deriveNameIfNeeded :: Name -> DecsQ
- deriveName :: Name -> DecsQ
- names :: Name a => a -> [String]
- class Name a where
- variableNamesFromTemplate :: String -> [String]
- rehole :: Expr -> Expr
- (>$$<) :: [Expr] -> [Expr] -> [Expr]
- funToVar :: Expr -> Expr
- recursexpr :: Int -> Expr -> Expr -> Expr
- apparentlyTerminates :: Expr -> Expr -> Bool
- mayNotEvaluateArgument :: Expr -> Bool
- compareSimplicity :: Expr -> Expr -> Ordering
- ifFor :: Typeable a => a -> Expr
- caseForOrd :: Typeable a => a -> Expr
- valuesBFS :: Expr -> [Expr]
- holesBFS :: Expr -> [Expr]
- fillBFS :: Expr -> Expr -> Expr
- ($$**) :: Expr -> Expr -> Maybe Expr
- ($$|<) :: Expr -> Expr -> Maybe Expr
- possibleHoles :: [Expr] -> [Expr]
- revaluate :: Typeable a => (Expr, Expr) -> Int -> Expr -> Maybe a
- reval :: Typeable a => (Expr, Expr) -> Int -> a -> Expr -> a
- useMatches :: [Expr] -> [Expr] -> [[(Expr, Expr)]]
- deholings :: Expr -> Expr -> [Expr]
- enumerateAppsFor :: Expr -> (Expr -> Bool) -> [Expr] -> [[Expr]]
- enumerateFillings :: Expr -> [[Expr]] -> [[Expr]]
- module Conjure.Utils
Documentation
module Data.Express
(-...-) :: Expr -> Expr -> Expr -> Expr #
enumFromThenTo
lifted over Expr
s but named as ",.."
for pretty-printing.
> (zero -...- two) ten [0,2..10] :: [Int]
enumFromThenTo' :: Expr -> Expr -> Expr -> Expr #
enumFromThenTo
lifted over Expr
s.
> enumFromThenTo' zero two ten enumFromThenTo 0 2 10 :: [Int]
(-...) :: Expr -> Expr -> Expr #
enumFromThen
lifted over Expr
s but named as ",.."
for pretty printing.
> zero -... ten [0,10..] :: [Int]
enumFromThen' :: Expr -> Expr -> Expr #
enumFromThen
lifted over Expr
s
> enumFromThen' zero ten enumFromThen 0 10 :: [Int]
(-..-) :: Expr -> Expr -> Expr #
enumFromTo
lifted over Expr
s but named as ".."
for pretty-printing.
> zero -..- four [0..4] :: [Int]
enumFromTo' :: Expr -> Expr -> Expr #
enumFromTo
lifted over Expr
s
> enumFromTo' zero four enumFromTo 0 4 :: [Int]
Function composition encoded as an Expr
:
> compose (.) :: (Int -> Int) -> (Int -> Int) -> Int -> Int
Nothing
bound to the Maybe
Int
type encoded as an Expr
.
This is an alias to nothingInt
.
caseOrdering :: Expr -> Expr -> Expr -> Expr -> Expr #
A function case :: Ordering -> a -> a -> a -> a
lifted over the Expr
type
that encodes case-of-LT-EQ-GT functionality.
This is properly displayed as a case-of-LT-EQ-GT expression.
(cf. caseBool
)
> caseOrdering (xx `compare'` yy) zero one two (case compare x y of LT -> 0; EQ -> 1; GT -> 2) :: Int
> evl $ caseOrdering (val EQ) (val 'l') (val 'e') (val 'g') :: Char 'e'
By convention cases are given in LT
, EQ
and GT
order
as LT < EQ < GT
and data Ordering = LT | EQ | GT
.
caseBool :: Expr -> Expr -> Expr -> Expr #
A function case :: Bool -> a -> a -> a
lifted over the Expr
type
that encodes case-of-False-True functionality.
This is properly displayed as a case-of-False-True expression.
> caseBool pp zero xx (case p of False -> 0; True -> x) :: Int
> zz -*- caseBool pp xx yy z * (case p of False -> x; True -> y) :: Int
> caseBool pp false true -||- caseBool qq true false (caseBool p of False -> False; True -> True) || (caseBool q of False -> True; True -> False) :: Bool
> evl $ caseBool true (val 'f') (val 't') :: Char 't'
By convention, the False
case comes before True
as False < True
and data Bool = False | True
.
When evaluating, this is equivalent to if with arguments reversed.
Instead of using this, you are perhaps better of using if encoded as an
expression. This is just here to be consistent with caseOrdering
.
if' :: Expr -> Expr -> Expr -> Expr #
A function if :: Bool -> a -> a -> a
lifted over the Expr
type
that encodes if-then-else functionality.
This is properly displayed as an if-then-else.
> if' pp zero xx (if p then 0 else x) :: Int
> zz -*- if' pp xx yy z * (if p then x else y) :: Int
> if' pp false true -||- if' qq true false (if p then False else True) || (if q then True else False) :: Bool
> evl $ if' true (val 't') (val 'f') :: Char 't'
(-<-) :: Expr -> Expr -> Expr infix 4 #
Constructs a less-than inequation between two Expr
s.
> xx -<- zero x < 0 :: Bool
> cc -<- bee c < 'b' :: Bool
(-<=-) :: Expr -> Expr -> Expr infix 4 #
Constructs a less-than-or-equal inequation between two Expr
s.
> xx -<=- zero x <= 0 :: Bool
> cc -<=- ae c <= 'a' :: Bool
(-/=-) :: Expr -> Expr -> Expr infix 4 #
Constructs an inequation between two Expr
s.
> xx -/=- zero x /= 0 :: Bool
> cc -/=- ae c /= 'a' :: Bool
emptyString :: Expr #
A variable function h
of 'Int -> Int' type lifted over the Expr
type.
> hh zz h z :: Int
A variable function g
of 'Int -> Int' type lifted over the Expr
type.
> gg yy g y :: Int
> gg minusTwo gg (-2) :: Int
A variable function f
of 'Int -> Int' type lifted over the Expr
type.
> ff xx f x :: Int
> ff one f 1 :: Int
(-==>-) :: Expr -> Expr -> Expr infixr 0 #
The function ==>
lifted over Expr
s.
> false -==>- true False ==> True :: Bool
> evl $ false -==>- true :: Bool True
fastMostSpecificVariation :: Expr -> Expr #
A faster version of mostSpecificCanonicalVariation
that disregards name clashes across different types.
Consider using mostSpecificCanonicalVariation
instead.
The same caveats of fastCanonicalVariations
do apply here.
fastMostGeneralVariation :: Expr -> Expr #
A faster version of mostGeneralCanonicalVariation
that disregards name clashes across different types.
Consider using mostGeneralCanonicalVariation
instead.
The same caveats of fastCanonicalVariations
do apply here.
fastCanonicalVariations :: Expr -> [Expr] #
A faster version of canonicalVariations
that
disregards name clashes across different types.
Results are confusing to the user
but fine for Express which differentiates
between variables with the same name but different types.
Without applying canonicalize
, the following Expr
may seem to have only one variable:
> fastCanonicalVariations $ i_ -+- ord' c_ [x + ord x :: Int]
Where in fact it has two, as the second x
has a different type.
Applying canonicalize
disambiguates:
> map canonicalize . fastCanonicalVariations $ i_ -+- ord' c_ [x + ord c :: Int]
This function is useful when resulting Expr
s are
not intended to be presented to the user
but instead to be used by another function.
It is simply faster to skip the step where clashes are resolved.
mostSpecificCanonicalVariation :: Expr -> Expr #
Returns the most specific canonical variation of an Expr
by filling holes with variables.
> mostSpecificCanonicalVariation $ i_ x :: Int
> mostSpecificCanonicalVariation $ i_ -+- i_ x + x :: Int
> mostSpecificCanonicalVariation $ i_ -+- i_ -+- i_ (x + x) + x :: Int
> mostSpecificCanonicalVariation $ i_ -+- ord' c_ x + ord c :: Int
> mostSpecificCanonicalVariation $ i_ -+- i_ -+- ord' c_ (x + x) + ord c :: Int
> mostSpecificCanonicalVariation $ i_ -+- i_ -+- length' (c_ -:- unit c_) (x + x) + length (c:c:"") :: Int
In an expression without holes this functions just returns the given expression itself:
> mostSpecificCanonicalVariation $ val (0 :: Int) 0 :: Int
> mostSpecificCanonicalVariation $ ord' bee ord 'b' :: Int
This function is the same as taking the last
of canonicalVariations
but a bit faster.
mostGeneralCanonicalVariation :: Expr -> Expr #
Returns the most general canonical variation of an Expr
by filling holes with variables.
> mostGeneralCanonicalVariation $ i_ x :: Int
> mostGeneralCanonicalVariation $ i_ -+- i_ x + y :: Int
> mostGeneralCanonicalVariation $ i_ -+- i_ -+- i_ (x + y) + z :: Int
> mostGeneralCanonicalVariation $ i_ -+- ord' c_ x + ord c :: Int
> mostGeneralCanonicalVariation $ i_ -+- i_ -+- ord' c_ (x + y) + ord c :: Int
> mostGeneralCanonicalVariation $ i_ -+- i_ -+- length' (c_ -:- unit c_) (x + y) + length (c:d:"") :: Int
In an expression without holes this functions just returns the given expression itself:
> mostGeneralCanonicalVariation $ val (0 :: Int) 0 :: Int
> mostGeneralCanonicalVariation $ ord' bee ord 'b' :: Int
This function is the same as taking the head
of canonicalVariations
but a bit faster.
canonicalVariations :: Expr -> [Expr] #
Returns all canonical variations of an Expr
by filling holes with variables.
Where possible, variations are listed
from most general to least general.
> canonicalVariations $ i_ [x :: Int]
> canonicalVariations $ i_ -+- i_ [ x + y :: Int , x + x :: Int ]
> canonicalVariations $ i_ -+- i_ -+- i_ [ (x + y) + z :: Int , (x + y) + x :: Int , (x + y) + y :: Int , (x + x) + y :: Int , (x + x) + x :: Int ]
> canonicalVariations $ i_ -+- ord' c_ [x + ord c :: Int]
> canonicalVariations $ i_ -+- i_ -+- ord' c_ [ (x + y) + ord c :: Int , (x + x) + ord c :: Int ]
> canonicalVariations $ i_ -+- i_ -+- length' (c_ -:- unit c_) [ (x + y) + length (c:d:"") :: Int , (x + y) + length (c:c:"") :: Int , (x + x) + length (c:d:"") :: Int , (x + x) + length (c:c:"") :: Int ]
In an expression without holes this functions just returns a singleton list with the expression itself:
> canonicalVariations $ val (0 :: Int) [0 :: Int]
> canonicalVariations $ ord' bee [ord 'b' :: Int]
When applying this to expressions already containing variables clashes are avoided and these variables are not touched:
> canonicalVariations $ i_ -+- ii -+- jj -+- i_ [ x + i + j + y :: Int , x + i + j + y :: Int ]
> canonicalVariations $ ii -+- jj [i + j :: Int]
> canonicalVariations $ xx -+- i_ -+- i_ -+- length' (c_ -:- unit c_) -+- yy [ (((x + z) + x') + length (c:d:"")) + y :: Int , (((x + z) + x') + length (c:c:"")) + y :: Int , (((x + z) + z) + length (c:d:"")) + y :: Int , (((x + z) + z) + length (c:c:"")) + y :: Int ]
isCanonical :: Expr -> Bool #
Returns whether an Expr
is canonical:
if applying canonicalize
is an identity
using names
as provided by preludeNameInstances
.
canonicalization :: Expr -> [(Expr, Expr)] #
Return a canonicalization of an Expr
that makes variable names appear in order
using names
as provided by preludeNameInstances
.
By using //-
it can canonicalize
Expr
s.
> canonicalization (gg yy -+- ff xx -+- gg xx) [ (x :: Int, y :: Int) , (f :: Int -> Int, g :: Int -> Int) , (y :: Int, x :: Int) , (g :: Int -> Int, f :: Int -> Int) ]
> canonicalization (yy -+- xx -+- yy) [ (x :: Int, y :: Int) , (y :: Int, x :: Int) ]
canonicalize :: Expr -> Expr #
Canonicalizes an Expr
so that variable names appear in order.
Variable names are taken from the preludeNameInstances
.
> canonicalize (xx -+- yy) x + y :: Int
> canonicalize (yy -+- xx) x + y :: Int
> canonicalize (xx -+- xx) x + x :: Int
> canonicalize (yy -+- yy) x + x :: Int
Constants are untouched:
> canonicalize (jj -+- (zero -+- abs' ii)) x + (y + abs y) :: Int
This also works for variable functions:
> canonicalize (gg yy -+- ff xx -+- gg xx) (f x + g y) + f y :: Int
isCanonicalWith :: (Expr -> [String]) -> Expr -> Bool #
Like isCanonical
but allows specifying
the list of variable names.
canonicalizationWith :: (Expr -> [String]) -> Expr -> [(Expr, Expr)] #
Like canonicalization
but allows customization
of the list of variable names.
(cf. lookupNames
, variableNamesFromTemplate
)
canonicalizeWith :: (Expr -> [String]) -> Expr -> Expr #
Like canonicalize
but allows customization
of the list of variable names.
(cf. lookupNames
, variableNamesFromTemplate
)
> canonicalizeWith (const ["i","j","k","l",...]) (xx -+- yy) i + j :: Int
The argument Expr
of the argument function allows
to provide a different list of names for different types:
> let namesFor e > | typ e == typeOf (undefined::Char) = variableNamesFromTemplate "c1" > | typ e == typeOf (undefined::Int) = variableNamesFromTemplate "i" > | otherwise = variableNamesFromTemplate "x"
> canonicalizeWith namesFor ((xx -+- ord' dd) -+- (ord' cc -+- yy)) (i + ord c1) + (ord c2 + j) :: Int
preludeNameInstances :: [Expr] #
validApps :: [Expr] -> Expr -> [Expr] #
Given a list of functional expressions and another expression, returns a list of valid applications.
listVarsWith :: [Expr] -> Expr -> [Expr] #
O(n+m).
Like lookupNames
but returns a list of variables encoded as Expr
s.
lookupNames :: [Expr] -> Expr -> [String] #
O(n+m).
A mix between lookupName
and names
:
this returns an infinite list of names
based on an instances list and an Expr
.
lookupName :: [Expr] -> Expr -> String #
mkComparison :: String -> [Expr] -> Expr -> Expr -> Expr #
O(n+m).
Like mkEquation
, mkComparisonLE
and mkComparisonLT
but allows providing the binary operator name.
When not possible, this function returns False
encoded as an Expr
.
isOrd :: [Expr] -> Expr -> Bool #
O(n+m).
Returns whether an Ord
instance exists in the given instances list
for the given Expr
.
> isOrd (reifyEqOrd (undefined :: Int)) (val (0::Int)) True
> isOrd (reifyEqOrd (undefined :: Int)) (val ([[[0::Int]]])) False
Given that the instances list has length m
and that the given Expr
has size n,
this function is O(n+m).
isEq :: [Expr] -> Expr -> Bool #
O(n+m).
Returns whether an Eq
instance exists in the given instances list
for the given Expr
.
> isEq (reifyEqOrd (undefined :: Int)) (val (0::Int)) True
> isEq (reifyEqOrd (undefined :: Int)) (val ([[[0::Int]]])) False
Given that the instances list has length m
and that the given Expr
has size n,
this function is O(n+m).
isOrdT :: [Expr] -> TypeRep -> Bool #
O(n).
Returns whether an Ord
instance exists in the given instances list
for the given TypeRep
.
> isOrdT (reifyEqOrd (undefined :: Int)) (typeOf (undefined :: Int)) True
> isOrdT (reifyEqOrd (undefined :: Int)) (typeOf (undefined :: [[[Int]]])) False
Given that the instances list has length n, this function is O(n).
isEqT :: [Expr] -> TypeRep -> Bool #
O(n).
Returns whether an Eq
instance exists in the given instances list
for the given TypeRep
.
> isEqT (reifyEqOrd (undefined :: Int)) (typeOf (undefined :: Int)) True
> isEqT (reifyEqOrd (undefined :: Int)) (typeOf (undefined :: [[[Int]]])) False
Given that the instances list has length n, this function is O(n).
lookupComparison :: String -> TypeRep -> [Expr] -> Maybe Expr #
O(n).
Lookups for a comparison function (:: a -> a -> Bool
)
with the given name and argument type.
mkNameWith :: Typeable a => String -> a -> [Expr] #
mkName :: Typeable a => (a -> String) -> [Expr] #
O(1).
Builds a reified Name
instance from the given name
function.
(cf. reifyName
, mkNameWith
)
mkOrdLessEqual :: Typeable a => (a -> a -> Bool) -> [Expr] #
mkOrd :: Typeable a => (a -> a -> Ordering) -> [Expr] #
O(1).
Builds a reified Ord
instance from the given compare
function.
(cf. reifyOrd
, mkOrdLessEqual
)
reifyName :: (Typeable a, Name a) => a -> [Expr] #
O(1).
Reifies a Name
instance into a list of Expr
s.
The list will contain name
for the given type.
(cf. mkName
, lookupName
, lookupNames
)
> reifyName (undefined :: Int) [name :: Int -> [Char]]
> reifyName (undefined :: Bool) [name :: Bool -> [Char]]
reifyEqOrd :: (Typeable a, Ord a) => a -> [Expr] #
reifyOrd :: (Typeable a, Ord a) => a -> [Expr] #
O(1).
Reifies an Ord
instance into a list of Expr
s.
The list will contain compare
, <=
and <
for the given type.
(cf. mkOrd
, mkOrdLessEqual
, mkComparisonLE
, mkComparisonLT
)
> reifyOrd (undefined :: Int) [ (<=) :: Int -> Int -> Bool , (<) :: Int -> Int -> Bool ]
> reifyOrd (undefined :: Bool) [ (<=) :: Bool -> Bool -> Bool , (<) :: Bool -> Bool -> Bool ]
> reifyOrd (undefined :: [Bool]) [ (<=) :: [Bool] -> [Bool] -> Bool , (<) :: [Bool] -> [Bool] -> Bool ]
reifyEq :: (Typeable a, Eq a) => a -> [Expr] #
O(1).
Reifies an Eq
instance into a list of Expr
s.
The list will contain ==
and /=
for the given type.
(cf. mkEq
, mkEquation
)
> reifyEq (undefined :: Int) [ (==) :: Int -> Int -> Bool , (/=) :: Int -> Int -> Bool ]
> reifyEq (undefined :: Bool) [ (==) :: Bool -> Bool -> Bool , (/=) :: Bool -> Bool -> Bool ]
> reifyEq (undefined :: String) [ (==) :: [Char] -> [Char] -> Bool , (/=) :: [Char] -> [Char] -> Bool ]
deriveExpressCascading :: Name -> DecsQ #
deriveExpressIfNeeded :: Name -> DecsQ #
Same as deriveExpress
but does not warn when instance already exists
(deriveExpress
is preferable).
deriveExpress :: Name -> DecsQ #
class (Show a, Typeable a) => Express a where #
Express
typeclass instances provide an expr
function
that allows values to be deeply encoded as applications of Expr
s.
expr False = val False expr (Just True) = value "Just" (Just :: Bool -> Maybe Bool) :$ val True
The function expr
can be contrasted with the function val
:
val
always encodes values as atomicValue
Expr
s -- shallow encoding.expr
ideally encodes expressions as applications (:$
) betweenValue
Expr
s -- deep encoding.
Depending on the situation, one or the other may be desirable.
Instances can be automatically derived using the TH function
deriveExpress
.
The following example shows a datatype and its instance:
data Stack a = Stack a (Stack a) | Empty
instance Express a => Express (Stack a) where expr s@(Stack x y) = value "Stack" (Stack ->>: s) :$ expr x :$ expr y expr s@Empty = value "Empty" (Empty -: s)
To declare expr
it may be useful to use auxiliary type binding operators:
-:
, ->:
, ->>:
, ->>>:
, ->>>>:
, ->>>>>:
, ...
For types with atomic values, just declare expr = val
Instances
O(n).
Folds a list of Expr
s into a single Expr
.
(cf. unfold
)
This always generates an ill-typed expression.
fold [val False, val True, val (1::Int)] [False,True,1] :: ill-typed # ExprList $ Bool #
This is useful when applying transformations on lists of Expr
s, such as
canonicalize
,
mapValues
or
canonicalVariations
.
> let ii = var "i" (undefined::Int) > let kk = var "k" (undefined::Int) > let qq = var "q" (undefined::Bool) > let notE = value "not" not > unfold . canonicalize . fold $ [ii,kk,notE :$ qq, notE :$ val False] [x :: Int,y :: Int,not p :: Bool,not False :: Bool]
unfoldTrio :: Expr -> (Expr, Expr, Expr) #
O(1).
Unfolds an Expr
representing a trio/triple.
This reverses the effect of foldTrio
.
> value ",," ((,,) :: Bool->Bool->Bool->(Bool,Bool,Bool)) :$ val True :$ val False :$ val True (True,False,True) :: (Bool,Bool,Bool) > unfoldTrio $ value ",," ((,,) :: Bool->Bool->Bool->(Bool,Bool,Bool)) :$ val True :$ val False :$ val True (True :: Bool,False :: Bool,True :: Bool)
(cf. unfoldPair
)
foldTrio :: (Expr, Expr, Expr) -> Expr #
O(1).
Folds a trio/triple of Expr
values into a single Expr
.
(cf. unfoldTrio
)
This always generates an ill-typed expression as it uses a fake trio/triple constructor.
> foldTrio (val False, val (1::Int), val 'a') (False,1,'a') :: ill-typed # ExprTrio $ Bool #
> foldTrio (val (0::Int), val True, val 'b') (0,True,'b') :: ill-typed # ExprTrio $ Int #
This is useful when applying transformations on pairs of Expr
s, such as
canonicalize
,
mapValues
or
canonicalVariations
.
> let ii = var "i" (undefined::Int) > let kk = var "k" (undefined::Int) > let zz = var "z" (undefined::Int) > unfoldPair $ canonicalize $ foldPair (ii,kk,zz) (x :: Int,y :: Int,z :: Int)
unfoldPair :: Expr -> (Expr, Expr) #
foldPair :: (Expr, Expr) -> Expr #
O(1).
Folds a pair of Expr
values into a single Expr
.
(cf. unfoldPair
)
This always generates an ill-typed expression, as it uses a fake pair constructor.
> foldPair (val False, val (1::Int)) (False,1) :: ill-typed # ExprPair $ Bool #
> foldPair (val (0::Int), val True) (0,True) :: ill-typed # ExprPair $ Int #
This is useful when applying transformations on pairs of Expr
s, such as
canonicalize
,
mapValues
or
canonicalVariations
.
> let ii = var "i" (undefined::Int) > let kk = var "k" (undefined::Int) > unfoldPair $ canonicalize $ foldPair (ii,kk) (x :: Int,y :: Int)
O(n).
Folds a list of Expr
with function application (:$
).
This reverses the effect of unfoldApp
.
foldApp [e0] = e0 foldApp [e0,e1] = e0 :$ e1 foldApp [e0,e1,e2] = e0 :$ e1 :$ e2 foldApp [e0,e1,e2,e3] = e0 :$ e1 :$ e2 :$ e3
Remember :$
is left-associative, so:
foldApp [e0] = e0 foldApp [e0,e1] = (e0 :$ e1) foldApp [e0,e1,e2] = ((e0 :$ e1) :$ e2) foldApp [e0,e1,e2,e3] = (((e0 :$ e1) :$ e2) :$ e3)
This function may produce an ill-typed expression.
fill :: Expr -> [Expr] -> Expr #
Fill holes in an expression with the given list.
> let i_ = hole (undefined :: Int) > let e1 -+- e2 = value "+" ((+) :: Int -> Int -> Int) :$ e1 :$ e2 > let xx = var "x" (undefined :: Int) > let yy = var "y" (undefined :: Int)
> fill (i_ -+- i_) [xx, yy] x + y :: Int
> fill (i_ -+- i_) [xx, xx] x + x :: Int
> let one = val (1::Int)
> fill (i_ -+- i_) [one, one -+- one] 1 + (1 + 1) :: Int
This function silently remaining expressions:
> fill i_ [xx, yy] x :: Int
This function silently keeps remaining holes:
> fill (i_ -+- i_ -+- i_) [xx, yy] (x + y) + _ :: Int
This function silently skips remaining holes if one is not of the right type:
> fill (i_ -+- i_ -+- i_) [xx, val 'c', yy] (x + _) + _ :: Int
listVarsAsTypeOf :: String -> Expr -> [Expr] #
Generate an infinite list of variables
based on a template
and the type of a given Expr
.
(cf. listVars
)
> let one = val (1::Int) > putL 10 $ "x" `listVarsAsTypeOf` one [ x :: Int , y :: Int , z :: Int , x' :: Int , ... ]
> let false = val False > putL 10 $ "p" `listVarsAsTypeOf` false [ p :: Bool , q :: Bool , r :: Bool , p' :: Bool , ... ]
listVars :: Typeable a => String -> a -> [Expr] #
Generate an infinite list of variables
based on a template and a given type.
(cf. listVarsAsTypeOf
)
> putL 10 $ listVars "x" (undefined :: Int) [ x :: Int , y :: Int , z :: Int , x' :: Int , y' :: Int , z' :: Int , x'' :: Int , ... ]
> putL 10 $ listVars "p" (undefined :: Bool) [ p :: Bool , q :: Bool , r :: Bool , p' :: Bool , q' :: Bool , r' :: Bool , p'' :: Bool , ... ]
isComplete :: Expr -> Bool #
O(n). Returns whether an expression is complete. A complete expression is one without holes.
> isComplete $ hole (undefined :: Bool) False
> isComplete $ value "not" not :$ val True True
> isComplete $ value "not" not :$ hole (undefined :: Bool) False
isComplete
is the negation of hasHole
.
isComplete = not . hasHole
isComplete
is to hasHole
what
isGround
is to hasVar
.
O(n). Returns whether an expression contains a hole
> hasHole $ hole (undefined :: Bool) True
> hasHole $ value "not" not :$ val True False
> hasHole $ value "not" not :$ hole (undefined :: Bool) True
O(n^2).
Lists all holes in an expression without repetitions.
(cf. holes
)
> nubHoles $ hole (undefined :: Bool) [_ :: Bool]
> nubHoles $ value "&&" (&&) :$ hole (undefined :: Bool) :$ hole (undefined :: Bool) [_ :: Bool]
> nubHoles $ hole (undefined :: Bool->Bool) :$ hole (undefined::Bool) [_ :: Bool,_ :: Bool -> Bool]
Runtime averages to
O(n log n) on evenly distributed expressions
such as (f x + g y) + (h z + f w)
;
and to O(n^2) on deep expressions
such as f (g (h (f (g (h x)))))
.
O(n).
Lists all holes in an expression, in order and with repetitions.
(cf. nubHoles
)
> holes $ hole (undefined :: Bool) [_ :: Bool]
> holes $ value "&&" (&&) :$ hole (undefined :: Bool) :$ hole (undefined :: Bool) [_ :: Bool,_ :: Bool]
> holes $ hole (undefined :: Bool->Bool) :$ hole (undefined::Bool) [_ :: Bool -> Bool,_ :: Bool]
hole :: Typeable a => a -> Expr #
O(1).
Creates an Expr
representing a typed hole of the given argument type.
> hole (undefined :: Int) _ :: Int
> hole (undefined :: Maybe String) _ :: Maybe [Char]
A hole is represented as a variable with no name or
a value named "_"
:
hole x = var "" x hole x = value "_" x
holeAsTypeOf :: Expr -> Expr #
varAsTypeOf :: String -> Expr -> Expr #
renameVarsBy :: (String -> String) -> Expr -> Expr #
Rename variables in an Expr
.
> renameVarsBy (++ "'") (xx -+- yy) x' + y' :: Int
> renameVarsBy (++ "'") (yy -+- (zz -+- xx)) (y' + (z' + x')) :: Int
> renameVarsBy (++ "1") (abs' xx) abs x1 :: Int
> renameVarsBy (++ "2") $ abs' (xx -+- yy) abs (x2 + y2) :: Int
NOTE: this will affect holes!
(//) :: Expr -> [(Expr, Expr)] -> Expr #
O(n*n*m).
Substitute subexpressions in an expression
from the given list of substitutions.
(cf. mapSubexprs
).
Please consider using //-
if you are replacing just terminal values
as it is faster.
Given that:
> let xx = var "x" (undefined :: Int) > let yy = var "y" (undefined :: Int) > let zz = var "z" (undefined :: Int) > let xx -+- yy = value "+" ((+) :: Int->Int->Int) :$ xx :$ yy
Then:
> ((xx -+- yy) -+- (yy -+- zz)) // [(xx -+- yy, yy), (yy -+- zz, yy)] y + y :: Int
> ((xx -+- yy) -+- zz) // [(xx -+- yy, zz), (zz, xx -+- yy)] z + (x + y) :: Int
Replacement happens only once with outer expressions having more precedence than inner expressions.
> (xx -+- yy) // [(yy,xx), (xx -+- yy,zz), (zz,xx)] z :: Int
Given that the argument list has length m, this function is O(n*n*m). Remember that since n is the size of an expression, comparing two expressions is O(n) in the worst case, and we may need to compare with n subexpressions in the worst case.
(//-) :: Expr -> [(Expr, Expr)] -> Expr #
O(n*m).
Substitute occurrences of values in an expression
from the given list of substitutions.
(cf. mapValues
)
Given that:
> let xx = var "x" (undefined :: Int) > let yy = var "y" (undefined :: Int) > let zz = var "z" (undefined :: Int) > let xx -+- yy = value "+" ((+) :: Int->Int->Int) :$ xx :$ yy
Then:
> ((xx -+- yy) -+- (yy -+- zz)) //- [(xx, yy), (zz, yy)] (y + y) + (y + y) :: Int
> ((xx -+- yy) -+- (yy -+- zz)) //- [(yy, yy -+- zz)] (x + (y + z)) + ((y + z) + z) :: Int
This function does not work for substituting non-terminal subexpressions:
> (xx -+- yy) //- [(xx -+- yy, zz)] x + y :: Int
Please use the slower //
if you want the above replacement to work.
Replacement happens only once:
> xx //- [(xx,yy), (yy,zz)] y :: Int
Given that the argument list has length m, this function is O(n*m).
mapSubexprs :: (Expr -> Maybe Expr) -> Expr -> Expr #
O(n*m).
Substitute subexpressions of an expression using the given function.
Outer expressions have more precedence than inner expressions.
(cf. //
)
With:
> let xx = var "x" (undefined :: Int) > let yy = var "y" (undefined :: Int) > let zz = var "z" (undefined :: Int) > let plus = value "+" ((+) :: Int->Int->Int) > let times = value "*" ((*) :: Int->Int->Int) > let xx -+- yy = plus :$ xx :$ yy > let xx -*- yy = times :$ xx :$ yy
> let pluswap (o :$ xx :$ yy) | o == plus = Just $ o :$ yy :$ xx | pluswap _ = Nothing
Then:
> mapSubexprs pluswap $ (xx -*- yy) -+- (yy -*- zz) y * z + x * y :: Int
> mapSubexprs pluswap $ (xx -+- yy) -*- (yy -+- zz) (y + x) * (z + y) :: Int
Substitutions do not stack, in other words a replaced expression or its subexpressions are not further replaced:
> mapSubexprs pluswap $ (xx -+- yy) -+- (yy -+- zz) (y + z) + (x + y) :: Int
Given that the argument function is O(m), this function is O(n*m).
mapConsts :: (Expr -> Expr) -> Expr -> Expr #
O(n*m). Applies a function to all terminal constants in an expression.
Given that:
> let one = val (1 :: Int) > let two = val (2 :: Int) > let xx -+- yy = value "+" ((+) :: Int->Int->Int) :$ xx :$ yy > let intToZero e = if typ e == typ zero then zero else e
Then:
> one -+- (two -+- xx) 1 + (2 + x) :: Int
> mapConsts intToZero (one -+- (two -+- xx)) 0 + (0 + x) :: Integer
Given that the argument function is O(m), this function is O(n*m).
mapVars :: (Expr -> Expr) -> Expr -> Expr #
O(n*m). Applies a function to all variables in an expression.
Given that:
> let primeify e = if isVar e | then case e of (Value n d) -> Value (n ++ "'") d | else e > let xx = var "x" (undefined :: Int) > let yy = var "y" (undefined :: Int) > let xx -+- yy = value "+" ((+) :: Int->Int->Int) :$ xx :$ yy
Then:
> xx -+- yy x + y :: Int
> primeify xx x' :: Int
> mapVars primeify $ xx -+- yy x' + y' :: Int
> mapVars (primeify . primeify) $ xx -+- yy x'' + y'' :: Int
Given that the argument function is O(m), this function is O(n*m).
mapValues :: (Expr -> Expr) -> Expr -> Expr #
O(n*m).
Applies a function to all terminal values in an expression.
(cf. //-
)
Given that:
> let zero = val (0 :: Int) > let one = val (1 :: Int) > let two = val (2 :: Int) > let three = val (3 :: Int) > let xx -+- yy = value "+" ((+) :: Int->Int->Int) :$ xx :$ yy > let intToZero e = if typ e == typ zero then zero else e
Then:
> one -+- (two -+- three) 1 + (2 + 3) :: Int
> mapValues intToZero $ one -+- (two -+- three) 0 + (0 + 0) :: Integer
Given that the argument function is O(m), this function is O(n*m).
isSubexprOf :: Expr -> Expr -> Bool #
O(n^2).
Checks if an Expr
is a subexpression of another.
> (xx -+- yy) `isSubexprOf` (zz -+- (xx -+- yy)) True
> (xx -+- yy) `isSubexprOf` abs' (yy -+- xx) False
> xx `isSubexprOf` yy False
hasInstanceOf :: Expr -> Expr -> Bool #
encompasses :: Expr -> Expr -> Bool #
Given two Expr
s,
checks if the first expression
encompasses the second expression
in terms of variables.
This is equivalent to flipping the arguments of isInstanceOf
.
zero `encompasses` xx = False xx `encompasses` zero = True
isInstanceOf :: Expr -> Expr -> Bool #
Given two Expr
s,
checks if the first expression
is an instance of the second
in terms of variables.
(cf. encompasses
, hasInstanceOf
)
> let zero = val (0::Int) > let one = val (1::Int) > let xx = var "x" (undefined :: Int) > let yy = var "y" (undefined :: Int) > let e1 -+- e2 = value "+" ((+)::Int->Int->Int) :$ e1 :$ e2
one `isInstanceOf` one = True xx `isInstanceOf` xx = True yy `isInstanceOf` xx = True zero `isInstanceOf` xx = True xx `isInstanceOf` zero = False one `isInstanceOf` zero = False (xx -+- (yy -+- xx)) `isInstanceOf` (xx -+- yy) = True (yy -+- (yy -+- xx)) `isInstanceOf` (xx -+- yy) = True (zero -+- (yy -+- xx)) `isInstanceOf` (zero -+- yy) = True (one -+- (yy -+- xx)) `isInstanceOf` (zero -+- yy) = False
matchWith :: [(Expr, Expr)] -> Expr -> Expr -> Maybe [(Expr, Expr)] #
Like match
but allowing predefined bindings.
matchWith [(xx,zero)] (zero -+- one) (xx -+- yy) = Just [(xx,zero), (yy,one)] matchWith [(xx,one)] (zero -+- one) (xx -+- yy) = Nothing
match :: Expr -> Expr -> Maybe [(Expr, Expr)] #
Given two expressions, returns a Just
list of matches
of subexpressions of the first expressions
to variables in the second expression.
Returns Nothing
when there is no match.
> let zero = val (0::Int) > let one = val (1::Int) > let xx = var "x" (undefined :: Int) > let yy = var "y" (undefined :: Int) > let e1 -+- e2 = value "+" ((+)::Int->Int->Int) :$ e1 :$ e2
> (zero -+- one) `match` (xx -+- yy) Just [(y :: Int,1 :: Int),(x :: Int,0 :: Int)]
> (zero -+- (one -+- two)) `match` (xx -+- yy) Just [(y :: Int,1 + 2 :: Int),(x :: Int,0 :: Int)]
> (zero -+- (one -+- two)) `match` (xx -+- (yy -+- yy)) Nothing
In short:
(zero -+- one) `match` (xx -+- yy) = Just [(xx,zero), (yy,one)] (zero -+- (one -+- two)) `match` (xx -+- yy) = Just [(xx,zero), (yy,one-+-two)] (zero -+- (one -+- two)) `match` (xx -+- (yy -+- yy)) = Nothing
O(n).
Returns the maximum height of a given expression
given by the maximum number of nested function applications.
Curried function application is counted each time,
i.e. the application of a two argument function
increases the depth of its first argument by two
and of its second argument by one.
(cf. depth
)
With:
zero = val (0 :: Int) one = val (1 :: Int) two = val (2 :: Int) const' xx yy = value "const" (const :: Int->Int->Int) :$ xx :$ yy abs' xx = value "abs" (abs :: Int->Int) :$ xx
Then:
> height zero 1
> height (abs' one) 2
> height ((const' one) two) 3
> height ((const' (abs' one)) two) 4
> height ((const' one) (abs' two)) 3
Flipping arguments of applications in subterms may change the result of the function.
O(n).
Returns the maximum depth of a given expression
given by the maximum number of nested function applications.
Curried function application is counted only once,
i.e. the application of a two argument function
increases the depth of both its arguments by one.
(cf. height
)
With
zero = val (0 :: Int) one = val (1 :: Int) two = val (2 :: Int) xx -+- yy = value "+" ((+) :: Int->Int->Int) :$ xx :$ yy abs' xx = value "abs" (abs :: Int->Int) :$ xx
> depth zero 1
> depth (one -+- two) 2
> depth (abs' one -+- two) 3
Flipping arguments of applications in any of the subterms does not affect the result.
O(n). Returns the size of the given expression, i.e. the number of terminal values in it.
zero = val (0 :: Int) one = val (1 :: Int) two = val (2 :: Int) xx -+- yy = value "+" ((+) :: Int->Int->Int) :$ xx :$ yy abs' xx = value "abs" (abs :: Int->Int) :$ xx
> size zero 1
> size (one -+- two) 3
> size (abs' one) 2
O(n). Return the arity of the given expression, i.e. the number of arguments that its type takes.
> arity (val (0::Int)) 0
> arity (val False) 0
> arity (value "id" (id :: Int -> Int)) 1
> arity (value "const" (const :: Int -> Int -> Int)) 2
> arity (one -+- two) 0
O(n^2).
Lists all variables in an expression without repetitions.
(cf. vars
)
> nubVars (yy -+- xx) [ x :: Int , y :: Int ]
> nubVars (xx -+- (yy -+- xx)) [ x :: Int , y :: Int ]
> nubVars (zero -+- (one -*- two)) []
> nubVars (pp -&&- true) [p :: Bool]
Runtime averages to
O(n log n) on evenly distributed expressions
such as (f x + g y) + (h z + f w)
;
and to O(n^2) on deep expressions
such as f (g (h (f (g (h x)))))
.
O(n).
Lists all variables in an expression in order and with repetitions.
(cf. nubVars
)
> vars (xx -+- yy) [ x :: Int , y :: Int ]
> vars (xx -+- (yy -+- xx)) [ x :: Int , y :: Int , x :: Int ]
> vars (zero -+- (one -*- two)) []
> vars (pp -&&- true) [p :: Bool]
O(n^2).
List terminal constants in an expression without repetitions.
(cf. consts
)
> nubConsts (xx -+- yy) [ (+) :: Int -> Int -> Int ]
> nubConsts (xx -+- (yy -+- zz)) [ (+) :: Int -> Int -> Int ]
> nubConsts (pp -&&- true) [ True :: Bool , (&&) :: Bool -> Bool -> Bool ]
Runtime averages to
O(n log n) on evenly distributed expressions
such as (f x + g y) + (h z + f w)
;
and to O(n^2) on deep expressions
such as f (g (h (f (g (h x)))))
.
O(n).
List terminal constants in an expression in order and with repetitions.
(cf. nubConsts
)
> consts (xx -+- yy) [ (+) :: Int -> Int -> Int ]
> consts (xx -+- (yy -+- zz)) [ (+) :: Int -> Int -> Int , (+) :: Int -> Int -> Int ]
> consts (zero -+- (one -*- two)) [ (+) :: Int -> Int -> Int , 0 :: Int , (*) :: Int -> Int -> Int , 1 :: Int , 2 :: Int ]
> consts (pp -&&- true) [ (&&) :: Bool -> Bool -> Bool , True :: Bool ]
O(n^2).
Lists all terminal values in an expression without repetitions.
(cf. values
)
> nubValues (xx -+- yy) [ x :: Int , y :: Int , (+) :: Int -> Int -> Int
]
> nubValues (xx -+- (yy -+- zz)) [ x :: Int , y :: Int , z :: Int , (+) :: Int -> Int -> Int ]
> nubValues (zero -+- (one -*- two)) [ 0 :: Int , 1 :: Int , 2 :: Int , (*) :: Int -> Int -> Int , (+) :: Int -> Int -> Int ]
> nubValues (pp -&&- pp) [ p :: Bool , (&&) :: Bool -> Bool -> Bool ]
Runtime averages to
O(n log n) on evenly distributed expressions
such as (f x + g y) + (h z + f w)
;
and to O(n^2) on deep expressions
such as f (g (h (f (g (h x)))))
.
O(n).
Lists all terminal values in an expression in order and with repetitions.
(cf. nubValues
)
> values (xx -+- yy) [ (+) :: Int -> Int -> Int , x :: Int , y :: Int ]
> values (xx -+- (yy -+- zz)) [ (+) :: Int -> Int -> Int , x :: Int , (+) :: Int -> Int -> Int , y :: Int , z :: Int ]
> values (zero -+- (one -*- two)) [ (+) :: Int -> Int -> Int , 0 :: Int , (*) :: Int -> Int -> Int , 1 :: Int , 2 :: Int ]
> values (pp -&&- true) [ (&&) :: Bool -> Bool -> Bool , p :: Bool , True :: Bool ]
nubSubexprs :: Expr -> [Expr] #
O(n^3) for full evaluation.
Lists all subexpressions of a given expression without repetitions.
This includes the expression itself and partial function applications.
(cf. subexprs
)
> nubSubexprs (xx -+- yy) [ x :: Int , y :: Int , (+) :: Int -> Int -> Int , (x +) :: Int -> Int , x + y :: Int ]
> nubSubexprs (pp -&&- (pp -&&- true)) [ p :: Bool , True :: Bool , (&&) :: Bool -> Bool -> Bool , (p &&) :: Bool -> Bool , p && True :: Bool , p && (p && True) :: Bool ]
Runtime averages to
O(n^2 log n) on evenly distributed expressions
such as (f x + g y) + (h z + f w)
;
and to O(n^3) on deep expressions
such as f (g (h (f (g (h x)))))
.
O(n) for the spine, O(n^2) for full evaluation.
Lists subexpressions of a given expression in order and with repetitions.
This includes the expression itself and partial function applications.
(cf. nubSubexprs
)
> subexprs (xx -+- yy) [ x + y :: Int , (x +) :: Int -> Int , (+) :: Int -> Int -> Int , x :: Int , y :: Int ]
> subexprs (pp -&&- (pp -&&- true)) [ p && (p && True) :: Bool , (p &&) :: Bool -> Bool , (&&) :: Bool -> Bool -> Bool , p :: Bool , p && True :: Bool , (p &&) :: Bool -> Bool , (&&) :: Bool -> Bool -> Bool , p :: Bool , True :: Bool ]
O(1).
Returns whether an Expr
is an application (:$
).
> isApp $ var "x" (undefined :: Int) False
> isApp $ val False False
> isApp $ value "not" not :$ var "p" (undefined :: Bool) True
This is equivalent to pattern matching the :$
constructor.
Properties:
isApp (e1 :$ e2) = True
isApp (Value e) = False
isApp = not . isValue
isApp e = not (isVar e) && not (isConst e)
O(1).
Returns whether an Expr
is a terminal value (Value
).
> isValue $ var "x" (undefined :: Int) True
> isValue $ val False True
> isValue $ value "not" not :$ var "p" (undefined :: Bool) False
This is equivalent to pattern matching the Value
constructor.
Properties:
isValue (Value e) = True
isValue (e1 :$ e2) = False
isValue = not . isApp
isValue e = isVar e || isConst e
O(n).
Returns whether a Expr
has no variables.
This is equivalent to "not . hasVar
".
The name "ground" comes from term rewriting.
> isGround $ value "not" not :$ val True True
> isGround $ value "&&" (&&) :$ var "p" (undefined :: Bool) :$ val True False
O(n).
Unfold a function application Expr
into a list of function and
arguments.
unfoldApp $ e0 = [e0] unfoldApp $ e0 :$ e1 = [e0,e1] unfoldApp $ e0 :$ e1 :$ e2 = [e0,e1,e2] unfoldApp $ e0 :$ e1 :$ e2 :$ e3 = [e0,e1,e2,e3]
Remember :$
is left-associative, so:
unfoldApp e0 = [e0] unfoldApp (e0 :$ e1) = [e0,e1] unfoldApp ((e0 :$ e1) :$ e2) = [e0,e1,e2] unfoldApp (((e0 :$ e1) :$ e2) :$ e3) = [e0,e1,e2,e3]
compareQuickly :: Expr -> Expr -> Ordering #
O(n).
A fast total order between Expr
s
that can be used when sorting Expr
values.
This is lazier than its counterparts
compareComplexity
and compareLexicographically
and tries to evaluate the given Expr
s as least as possible.
compareLexicographically :: Expr -> Expr -> Ordering #
O(n).
Lexicographical structural comparison of Expr
s
where variables < constants < applications
then types are compared before string representations.
> compareLexicographically one (one -+- one) LT > compareLexicographically one zero GT > compareLexicographically (xx -+- zero) (zero -+- xx) LT > compareLexicographically (zero -+- xx) (zero -+- xx) EQ
(cf. compareTy
)
This comparison is a total order.
compareComplexity :: Expr -> Expr -> Ordering #
O(n).
Compares the complexity of two Expr
s.
An expression e1 is strictly simpler than another expression e2
if the first of the following conditions to distingish between them is:
- e1 is smaller in size/length than e2,
e.g.:
x + y < x + (y + z)
; - or, e1 has more distinct variables than e2,
e.g.:
x + y < x + x
; - or, e1 has more variable occurrences than e2,
e.g.:
x + x < 1 + x
; - or, e1 has fewer distinct constants than e2,
e.g.:
1 + 1 < 0 + 1
.
They're otherwise considered of equal complexity,
e.g.: x + y
and y + z
.
> (xx -+- yy) `compareComplexity` (xx -+- (yy -+- zz)) LT
> (xx -+- yy) `compareComplexity` (xx -+- xx) LT
> (xx -+- xx) `compareComplexity` (one -+- xx) LT
> (one -+- one) `compareComplexity` (zero -+- one) LT
> (xx -+- yy) `compareComplexity` (yy -+- zz) EQ
> (zero -+- one) `compareComplexity` (one -+- zero) EQ
This comparison is not a total order.
O(n).
Returns a string representation of an expression.
Differently from show
(:: Expr -> String
)
this function does not include the type in the output.
> putStrLn $ showExpr (one -+- two) 1 + 2
> putStrLn $ showExpr $ (pp -||- true) -&&- (qq -||- false) (p || True) && (q || False)
showPrecExpr :: Int -> Expr -> String #
O(n).
Like showExpr
but allows specifying the surrounding precedence.
> showPrecExpr 6 (one -+- two) "1 + 2"
> showPrecExpr 7 (one -+- two) "(1 + 2)"
showOpExpr :: String -> Expr -> String #
O(n).
Like showPrecExpr
but
the precedence is taken from the given operator name.
> showOpExpr "*" (two -*- three) "(2 * 3)"
> showOpExpr "+" (two -*- three) "2 * 3"
To imply that the surrounding environment is a function application,
use " "
as the given operator.
> showOpExpr " " (two -*- three) "(2 * 3)"
toDynamic :: Expr -> Maybe Dynamic #
O(n).
Evaluates an expression to a terminal Dynamic
value when possible.
Returns Nothing
otherwise.
> toDynamic $ val (123 :: Int) :: Maybe Dynamic Just <<Int>>
> toDynamic $ value "abs" (abs :: Int -> Int) :$ val (-1 :: Int) Just <<Int>>
> toDynamic $ value "abs" (abs :: Int -> Int) :$ val 'a' Nothing
eval :: Typeable a => a -> Expr -> a #
O(n). Evaluates an expression when possible (correct type). Returns a default value otherwise.
> let two = val (2 :: Int) > let three = val (3 :: Int) > let e1 -+- e2 = value "+" ((+) :: Int->Int->Int) :$ e1 :$ e2
> eval 0 $ two -+- three :: Int 5
> eval 'z' $ two -+- three :: Char 'z'
> eval 0 $ two -+- val '3' :: Int 0
evaluate :: Typeable a => Expr -> Maybe a #
O(n).
Just
the value of an expression when possible (correct type),
Nothing
otherwise.
This does not catch errors from undefined
Dynamic
value
s.
> let one = val (1 :: Int) > let bee = val 'b' > let negateE = value "negate" (negate :: Int -> Int)
> evaluate one :: Maybe Int Just 1
> evaluate one :: Maybe Char Nothing
> evaluate bee :: Maybe Int Nothing
> evaluate bee :: Maybe Char Just 'b'
> evaluate $ negateE :$ one :: Maybe Int Just (-1)
> evaluate $ negateE :$ bee :: Maybe Int Nothing
isWellTyped :: Expr -> Bool #
O(n).
Returns whether the given Expr
is well typed.
(cf. isIllTyped
)
> isWellTyped (absE :$ val (1 :: Int)) True
> isWellTyped (absE :$ val 'b') False
isIllTyped :: Expr -> Bool #
O(n).
Returns whether the given Expr
is ill typed.
(cf. isWellTyped
)
> let one = val (1 :: Int) > let bee = val 'b' > let absE = value "abs" (abs :: Int -> Int)
> isIllTyped (absE :$ val (1 :: Int)) False
> isIllTyped (absE :$ val 'b') True
etyp :: Expr -> Either (TypeRep, TypeRep) TypeRep #
O(n). Computes the type of an expression returning either the type of the given expression when possible or when there is a type error, the pair of types which produced the error.
> let one = val (1 :: Int) > let bee = val 'b' > let absE = value "abs" (abs :: Int -> Int)
> etyp one Right Int
> etyp bee Right Char
> etyp absE Right (Int -> Int)
> etyp (absE :$ one) Right Int
> etyp (absE :$ bee) Left (Int -> Int, Char)
> etyp ((absE :$ bee) :$ one) Left (Int -> Int, Char)
O(n).
Computes the type of an expression. This raises errors, but this should
not happen if expressions are smart-constructed with $$
.
> let one = val (1 :: Int) > let bee = val 'b' > let absE = value "abs" (abs :: Int -> Int)
> typ one Int
> typ bee Char
> typ absE Int -> Int
> typ (absE :$ one) Int
> typ (absE :$ bee) *** Exception: type mismatch, cannot apply `Int -> Int' to `Char'
> typ ((absE :$ bee) :$ one) *** Exception: type mismatch, cannot apply `Int -> Int' to `Char'
var :: Typeable a => String -> a -> Expr #
O(1).
Creates an Expr
representing a variable with the given name and argument
type.
> var "x" (undefined :: Int) x :: Int
> var "u" (undefined :: ()) u :: ()
> var "xs" (undefined :: [Int]) xs :: [Int]
This function follows the underscore convention:
a variable is just a value
whose string representation
starts with underscore ('_'
).
($$) :: Expr -> Expr -> Maybe Expr #
O(n).
Creates an Expr
representing a function application.
Just
an Expr
application if the types match, Nothing
otherwise.
(cf. :$
)
> value "id" (id :: () -> ()) $$ val () Just (id () :: ())
> value "abs" (abs :: Int -> Int) $$ val (1337 :: Int) Just (abs 1337 :: Int)
> value "abs" (abs :: Int -> Int) $$ val 'a' Nothing
> value "abs" (abs :: Int -> Int) $$ val () Nothing
value :: Typeable a => String -> a -> Expr #
O(1).
It takes a string representation of a value and a value, returning an
Expr
with that terminal value.
For instances of Show
, it is preferable to use val
.
> value "0" (0 :: Integer) 0 :: Integer
> value "'a'" 'a' 'a' :: Char
> value "True" True True :: Bool
> value "id" (id :: Int -> Int) id :: Int -> Int
> value "(+)" ((+) :: Int -> Int -> Int) (+) :: Int -> Int -> Int
> value "sort" (sort :: [Bool] -> [Bool]) sort :: [Bool] -> [Bool]
Values of type Expr
represent objects or applications between objects.
Each object is encapsulated together with its type and string representation.
Values encoded in Expr
s are always monomorphic.
An Expr
can be constructed using:
val
, for values that areShow
instances;value
, for values that are notShow
instances, like functions;:$
, for applications betweenExpr
s.
> val False False :: Bool
> value "not" not :$ val False not False :: Bool
An Expr
can be evaluated using evaluate
, eval
or evl
.
> evl $ val (1 :: Int) :: Int 1
> evaluate $ val (1 :: Int) :: Maybe Bool Nothing
> eval 'a' (val 'b') 'b'
Show
ing a value of type Expr
will return a pretty-printed representation
of the expression together with its type.
> show (value "not" not :$ val False) "not False :: Bool"
Expr
is like Dynamic
but has support for applications and variables
(:$
, var
).
The var
underscore convention:
Functions that manipulate Expr
s usually follow the convention
where a value
whose String
representation starts with '_'
represents a var
iable.
Instances
Show Expr | Shows > show (value "not" not :$ val False) "not False :: Bool" |
Eq Expr | O(n). Does not evaluate values when comparing, but rather uses their representation as strings and their types. This instance works for ill-typed expressions. |
Ord Expr | O(n). Does not evaluate values when comparing, but rather uses their representation as strings and their types. This instance works for ill-typed expressions. Expressions come first
when they have smaller complexity ( |
deriveNameCascading :: Name -> DecsQ #
deriveNameIfNeeded :: Name -> DecsQ #
Same as deriveName
but does not warn when instance already exists
(deriveName
is preferable).
deriveName :: Name -> DecsQ #
names :: Name a => a -> [String] #
Returns na infinite list of variable names from the given type:
the result of variableNamesFromTemplate
after name
.
> names (undefined :: Int) ["x", "y", "z", "x'", "y'", "z'", "x''", "y''", "z''", ...]
> names (undefined :: Bool) ["p", "q", "r", "p'", "q'", "r'", "p''", "q''", "r''", ...]
> names (undefined :: [Int]) ["xs", "ys", "zs", "xs'", "ys'", "zs'", "xs''", "ys''", ...]
If we were to come up with a variable name for the given type
what name
would it be?
An instance for a given type Ty
is simply given by:
instance Name Ty where name _ = "x"
Examples:
> name (undefined :: Int) "x"
> name (undefined :: Bool) "p"
> name (undefined :: [Int]) "xs"
This is then used to generate an infinite list of variable names
:
> names (undefined :: Int) ["x", "y", "z", "x'", "y'", "z'", "x''", "y''", "z''", ...]
> names (undefined :: Bool) ["p", "q", "r", "p'", "q'", "r'", "p''", "q''", "r''", ...]
> names (undefined :: [Int]) ["xs", "ys", "zs", "xs'", "ys'", "zs'", "xs''", "ys''", ...]
Nothing
O(1).
Returns a name for a variable of the given argument's type.
> name (undefined :: Int) "x"
> name (undefined :: [Bool]) "ps"
> name (undefined :: [Maybe Integer]) "mxs"
The default definition is:
name _ = "x"
Instances
Name Int16 | |
Defined in Data.Express.Name | |
Name Int32 | |
Defined in Data.Express.Name | |
Name Int64 | |
Defined in Data.Express.Name | |
Name Int8 | |
Defined in Data.Express.Name | |
Name GeneralCategory | |
Defined in Data.Express.Name name :: GeneralCategory -> String # | |
Name Word16 | |
Defined in Data.Express.Name | |
Name Word32 | |
Defined in Data.Express.Name | |
Name Word64 | |
Defined in Data.Express.Name | |
Name Word8 | |
Defined in Data.Express.Name | |
Name Ordering | name (undefined :: Ordering) = "o" names (undefined :: Ordering) = ["o", "p", "q", "o'", ...] |
Defined in Data.Express.Name | |
Name A Source # | |
Defined in Conjure.Conjurable | |
Name B Source # | |
Defined in Conjure.Conjurable | |
Name C Source # | |
Defined in Conjure.Conjurable | |
Name D Source # | |
Defined in Conjure.Conjurable | |
Name E Source # | |
Defined in Conjure.Conjurable | |
Name F Source # | |
Defined in Conjure.Conjurable | |
Name Integer | name (undefined :: Integer) = "x" names (undefined :: Integer) = ["x", "y", "z", "x'", ...] |
Defined in Data.Express.Name | |
Name () | name (undefined :: ()) = "u" names (undefined :: ()) = ["u", "v", "w", "u'", "v'", ...] |
Defined in Data.Express.Name | |
Name Bool | name (undefined :: Bool) = "p" names (undefined :: Bool) = ["p", "q", "r", "p'", "q'", ...] |
Defined in Data.Express.Name | |
Name Char | name (undefined :: Char) = "c" names (undefined :: Char) = ["c", "d", "e", "c'", "d'", ...] |
Defined in Data.Express.Name | |
Name Double | name (undefined :: Double) = "x" names (undefined :: Double) = ["x", "y", "z", "x'", ...] |
Defined in Data.Express.Name | |
Name Float | name (undefined :: Float) = "x" names (undefined :: Float) = ["x", "y", "z", "x'", ...] |
Defined in Data.Express.Name | |
Name Int | name (undefined :: Int) = "x" names (undefined :: Int) = ["x", "y", "z", "x'", "y'", ...] |
Defined in Data.Express.Name | |
Name Word | |
Defined in Data.Express.Name | |
Name (Complex a) | name (undefined :: Complex) = "x" names (undefined :: Complex) = ["x", "y", "z", "x'", ...] |
Defined in Data.Express.Name | |
Name (Ratio a) | name (undefined :: Rational) = "q" names (undefined :: Rational) = ["q", "r", "s", "q'", ...] |
Defined in Data.Express.Name | |
Name a => Name (Maybe a) | names (undefined :: Maybe Int) = ["mx", "mx1", "mx2", ...] nemes (undefined :: Maybe Bool) = ["mp", "mp1", "mp2", ...] |
Defined in Data.Express.Name | |
Name a => Name [a] | names (undefined :: [Int]) = ["xs", "ys", "zs", "xs'", ...] names (undefined :: [Bool]) = ["ps", "qs", "rs", "ps'", ...] |
Defined in Data.Express.Name | |
(Name a, Name b) => Name (Either a b) | names (undefined :: Either Int Int) = ["exy", "exy1", ...] names (undefined :: Either Int Bool) = ["exp", "exp1", ...] |
Defined in Data.Express.Name | |
Name (a -> b) | names (undefined :: ()->()) = ["f", "g", "h", "f'", ...] names (undefined :: Int->Int) = ["f", "g", "h", ...] |
Defined in Data.Express.Name | |
(Name a, Name b) => Name (a, b) | names (undefined :: (Int,Int)) = ["xy", "zw", "xy'", ...] names (undefined :: (Bool,Bool)) = ["pq", "rs", "pq'", ...] |
Defined in Data.Express.Name | |
(Name a, Name b, Name c) => Name (a, b, c) | names (undefined :: (Int,Int,Int)) = ["xyz","uvw", ...] names (undefined :: (Int,Bool,Char)) = ["xpc", "xpc1", ...] |
Defined in Data.Express.Name | |
(Name a, Name b, Name c, Name d) => Name (a, b, c, d) | names (undefined :: ((),(),(),())) = ["uuuu", "uuuu1", ...] names (undefined :: (Int,Int,Int,Int)) = ["xxxx", ...] |
Defined in Data.Express.Name | |
(Name a, Name b, Name c, Name d, Name e) => Name (a, b, c, d, e) | |
Defined in Data.Express.Name | |
(Name a, Name b, Name c, Name d, Name e, Name f) => Name (a, b, c, d, e, f) | |
Defined in Data.Express.Name | |
(Name a, Name b, Name c, Name d, Name e, Name f, Name g) => Name (a, b, c, d, e, f, g) | |
Defined in Data.Express.Name | |
(Name a, Name b, Name c, Name d, Name e, Name f, Name g, Name h) => Name (a, b, c, d, e, f, g, h) | |
Defined in Data.Express.Name | |
(Name a, Name b, Name c, Name d, Name e, Name f, Name g, Name h, Name i) => Name (a, b, c, d, e, f, g, h, i) | |
Defined in Data.Express.Name | |
(Name a, Name b, Name c, Name d, Name e, Name f, Name g, Name h, Name i, Name j) => Name (a, b, c, d, e, f, g, h, i, j) | |
Defined in Data.Express.Name | |
(Name a, Name b, Name c, Name d, Name e, Name f, Name g, Name h, Name i, Name j, Name k) => Name (a, b, c, d, e, f, g, h, i, j, k) | |
Defined in Data.Express.Name | |
(Name a, Name b, Name c, Name d, Name e, Name f, Name g, Name h, Name i, Name j, Name k, Name l) => Name (a, b, c, d, e, f, g, h, i, j, k, l) | |
Defined in Data.Express.Name |
variableNamesFromTemplate :: String -> [String] #
Returns an infinite list of variable names based on the given template.
> variableNamesFromTemplate "x" ["x", "y", "z", "x'", "y'", ...]
> variableNamesFromTemplate "p" ["p", "q", "r", "p'", "q'", ...]
> variableNamesFromTemplate "xy" ["xy", "zw", "xy'", "zw'", "xy''", ...]
rehole :: Expr -> Expr Source #
Turns all variables of an expression into holes.
> rehole (xx -+- yy) _ + _ :: Int
recursexpr :: Int -> Expr -> Expr -> Expr Source #
Expands recursive calls on an expression until the given size limit is reached.
> recursexpr 6 (ff xx) (ff xx) f x :: Int
> recursexpr 6 (ff xx) (one -+- ff xx) 1 + (1 + (1 + (1 + f x))) :: Int
> recursexpr 6 (ff xx) (if' pp one (xx -*- ff xx)) (if p then 1 else x * (if p then 1 else x * f x)) :: Int
> recursexpr 6 (ff xx) (if' pp one (xx -*- ff (gg xx))) (if p then 1 else x * (if p then 1 else g x * f (g (g x)))) :: Int
apparentlyTerminates :: Expr -> Expr -> Bool Source #
Checks if the given recursive call apparently terminates. The first argument indicates the functional variable indicating the recursive call.
> apparentlyTerminates ffE (ff xx) False
> apparentlyTerminates ffE (if' pp zero (ff xx)) True
This function only allows recursion in the else clause:
> apparentlyTerminates ffE (if' pp (ff xx) zero) False
Of course, recursive calls as the condition are not allowed:
> apparentlyTerminates ffE (if' (odd' (ff xx)) zero zero) False
mayNotEvaluateArgument :: Expr -> Bool Source #
Checks if the given functional expression may refrain from evaluating its next argument.
> mayNotEvaluateArgument (plus :$ xx) False
> mayNotEvaluateArgument (andE :$ pp) True
This returns false for non-funcional value even if it involves an application which may not evaluate its argument.
> mayNotEvaluateArgument (andE :$ pp :$ qq) False
This currently works by checking if the function is an if, &&
or ||
.
compareSimplicity :: Expr -> Expr -> Ordering Source #
O(n).
Compares the simplicity of two Expr
s.
An expression e1 is strictly simpler than another expression e2
if the first of the following conditions to distingish between them is:
- e1 is smaller in size/length than e2,
e.g.:
x + y < x + (y + z)
; - or, e1 has less variable occurrences than e2,
- or, e1 has fewer distinct constants than e2,
e.g.:
1 + 1 < 0 + 1
.
They're otherwise considered of equal complexity,
e.g.: x + y
and y + z
.
> (xx -+- yy) `compareComplexity` (xx -+- (yy -+- zz)) LT
> (xx -+- yy) `compareComplexity` (xx -+- xx) EQ
> (xx -+- xx) `compareComplexity` (one -+- xx) GT
> (one -+- one) `compareComplexity` (zero -+- one) LT
> (xx -+- yy) `compareComplexity` (yy -+- zz) EQ
> (zero -+- one) `compareComplexity` (one -+- zero) EQ
ifFor :: Typeable a => a -> Expr Source #
Creates an if Expr
of the type of the given proxy.
> ifFor (undefined :: Int) if :: Bool -> Int -> Int -> Int
> ifFor (undefined :: String) if :: Bool -> [Char] -> [Char] -> [Char]
caseForOrd :: Typeable a => a -> Expr Source #
Creates a case Expr
of the type of the given proxy.
> caseForOrd (undefined :: Int) case :: Bool -> Int -> Int -> Int -> Int
> caseForOrd (undefined :: String) case :: Bool -> [Char] -> [Char] -> [Char] -> [Char]
($$**) :: Expr -> Expr -> Maybe Expr Source #
Like $$
but always works regardless of type.
Warning: just like :$
, this may produce ill-typed expressions.
> zero $$** zero Just (0 0 :: ill-typed # Int $ Int #)
Together with $$|<
, this function is unused
but is useful when experiment with the source
to see the effect of type-corrected
on pruning the search space.
($$|<) :: Expr -> Expr -> Maybe Expr Source #
Like $$
but relaxed to work on correct kinds.
> ordE $$|< zero Just (ord 0 :: ill-typed # Char -> Int $ Int #)
> zero $$|< zero Nothing
Warning: just like :$
, this may produce ill-typed expressions.
Together with $$**
, this function is unused
but is useful when experiment with the source
to see the effect of type-corrected
on pruning the search space.
possibleHoles :: [Expr] -> [Expr] Source #
Lists all distinct holes that are possible with the given Expr
s.
> possibleHoles [zero, one, plus] [_ :: Int,_ :: Int -> Int,_ :: Int -> Int -> Int]
> possibleHoles [ae, ordE] [_ :: Char,_ :: Int,_ :: Char -> Int]
useMatches :: [Expr] -> [Expr] -> [[(Expr, Expr)]] Source #
useMatches [xx,yy] [xx,yy] = [[(xx,xx), (yy,yy)]] useMatches [xx,yy] [yy,xx] = [[(xx,xx), (yy,yy)]] useMatches [yy,xx] [xx,yy] = [[(yy,yy), (xx,xx)]] useMatches [xx,yy] [xx,xx] = [] useMatches [xx,yy] [abs' xx, abs' yy] = [[(xx,abs' xx), (yy, abs' yy)]] useMatches [xx-:-xxs, yy-:-yys] [abs' xx, abs' yy] = [(xx-:-xxs, abs' xx), (yy-:-yys, abs' yy)]
deholings :: Expr -> Expr -> [Expr] Source #
Takes two expressions and returns all possible ways in which the first expression can appear once in one of the holes of the second expression.
> deholings zero (i_ -+- i_ -+- i_) [ (0 + _) + _ :: Int , (_ + 0) + _ :: Int , (_ + _) + 0 :: Int ]
> deholings zero (i_ -+- one -+- ord' c_) [(0 + 1) + ord _ :: Int]
enumerateAppsFor :: Expr -> (Expr -> Bool) -> [Expr] -> [[Expr]] Source #
Enumerate applications between values of the given list of primitives and of the given expressions's type.
Arguments:
- an
Expr
whose type we are interested in - a filtering function, returning
True
for the expressions to keep - a list of primitives to be used in building expression.
Result: a potentially infinite list of list of enumerated expressions
The enumeration here is type-directed for performance reasons.
module Conjure.Utils