-- | -- Module : Data.Express -- Copyright : (c) 2019-2024 Rudy Matela -- License : 3-Clause BSD (see the file LICENSE) -- Maintainer : Rudy Matela <rudy@matela.com.br> -- -- Express is a library for manipulating dynamically typed Haskell expressions. -- It's like "Data.Dynamic" but with support for encoding applications and -- variables. -- -- It provides the 'Expr' type and over a hundred functions for -- building, evaluating, comparing, folding, canonicalizing and matching -- 'Expr's. -- -- /Basics./ -- For types that are 'Show' instances, -- we can use 'val' to encode values as 'Expr's: -- -- > > let false = val False -- > > :t false -- > false :: Expr -- > > print false -- > False :: Bool -- -- As seen above, the 'Show' instance for 'Expr' produces a string with the -- encoded value and it's type. -- -- For types that aren't 'Show' instances, like functions, -- we can use 'value' to encode values as 'Expr's. -- -- > > let notE = value "not" not -- > > :t notE -- > notE :: Expr -- > > print notE -- > not :: Bool -> Bool -- -- Using ':$' we can apply function valued 'Expr's, to other Exprs. -- -- > > let notFalse = notE :$ false -- > > :t notFalse -- > notFalse :: Expr -- > > notFalse -- > not False :: Bool -- -- Using 'evaluate' or 'eval' we can evaluate 'Expr's -- back into a regular Haskell value. -- -- > > evaluate notFalse :: Maybe Bool -- > Just True -- > > evaluate notFalse :: Maybe Int -- > Nothing -- > > eval False notFalse -- > True -- > > eval (0::Int) notFalse -- > 0 -- -- /Example:/ -- Like with "Data.Dynamic", we can use Express to create heterogeneous lists: -- -- > > let xs = [val False, val True, val (1::Int), val (2::Int), val (3::Integer), val "123"] -- > > :t xs -- > xs :: [Expr] -- > > xs -- > [ False :: Bool -- > , True :: Bool -- > , 1 :: Int -- > , 2 :: Int -- > , 3 :: Integer -- > , "123" :: [Char] -- > ] -- -- We can then apply 'evaluate' to select values of different types: -- -- > > import Data.Maybe -- > > mapMaybe evaluate xs :: [Bool] -- > [False,True] -- > > mapMaybe evaluate xs :: [Int] -- > [1,2] -- > > mapMaybe evaluate xs :: [Integer] -- > [3] -- > > mapMaybe evaluate xs :: [String] -- > ["123"] -- -- If we define an heterogeneous list of functions encoded as 'Expr's: -- -- > > let fs = [value "not" not, value "&&" (&&), value "abs" (abs :: Int -> Int)] -- > > :t fs -- > fs :: [Expr] -- -- Using '$$' we can list the type correct applications -- between the two previously defined lists: -- -- > > catMaybes [f $$ x | f <- fs, x <- xs] -- > [ not False :: Bool -- > , not True :: Bool -- > , (False &&) :: Bool -> Bool -- > , (True &&) :: Bool -> Bool -- > , abs 1 :: Int -- > , abs 2 :: Int -- > ] -- -- Other uses of Express include: -- -- * generalizing counter-examples of property-based testing -- in <https://hackage.haskell.org/package/extrapolate Extrapolate>; -- * conjecturing equations based on the results of testing -- in <https://hackage.haskell.org/package/speculate Speculate>. -- -- In this documentation, -- the complexity of most functions is given in big O notation -- where /n/ is the size of the expression being manipulated or produced. -- There may still be a /m/ cost associated with the values stored in 'Expr's. {-# LANGUAGE CPP #-} module Data.Express ( -- -- -- Data.Express.Core exports -- -- -- -- * The Expr datatype Expr (..) -- ** Building Exprs , value , val , ($$) , var -- ** Evaluating Exprs , evaluate , eval , evl , typ , etyp , mtyp , toDynamic -- ** Boolean properties of Exprs , isValue , isApp , isVar , isConst , isIllTyped , isWellTyped , isFun , hasVar , hasHole , isGround , isComplete -- ** Comparing Exprs , compareComplexity , compareLexicographically , compareQuickly -- ** Properties of Exprs , arity , size , depth , height -- ** Showing Exprs , showExpr , showPrecExpr , showOpExpr -- * Subexpressions -- ** Listing subexpressions , subexprs , values , vars , consts , nubSubexprs , nubValues , nubVars , nubConsts -- -- -- Data.Express.Basic exports -- -- -- , (>$$<) , (>$$) , ($$<) -- -- -- Data.Express.Map exports -- -- -- -- ** Mapping subexpressions , mapValues , mapVars , mapConsts , mapSubexprs , (//-) , (//) , renameVarsBy -- -- -- Data.Express.Hole exports -- -- -- -- * Variables and holes -- ** Creating variables , varAsTypeOf , listVars , listVarsAsTypeOf -- ** Typed holes , hole , isHole , holes , nubHoles , holeAsTypeOf , fill -- -- -- Data.Express.Fold exports -- -- -- -- * Juggling Exprs -- ** Folding Exprs , fold , unfold , foldPair , unfoldPair , foldTrio , unfoldTrio , foldApp , unfoldApp -- -- -- Data.Express.Canon exports -- -- -- -- ** Canonicalizing Exprs , canonicalize , canonicalizeWith , canonicalization , canonicalizationWith , isCanonical , isCanonicalWith , canonicalVariations , mostGeneralCanonicalVariation , mostSpecificCanonicalVariation , fastCanonicalVariations , fastMostGeneralVariation , fastMostSpecificVariation -- -- -- Data.Express.Match exports -- -- -- -- ** Matching Exprs , match , matchWith , isInstanceOf , hasInstanceOf , isSubexprOf , encompasses -- -- -- Data.Express.Express exports -- -- -- -- * Typeclasses -- ** The Express typeclass , Express (..) , deriveExpress , deriveExpressCascading , deriveExpressIfNeeded -- -- -- Data.Express.Name exports -- -- -- -- ** The Name typeclass , Name (..) , names , variableNamesFromTemplate , deriveName , deriveNameCascading , deriveNameIfNeeded -- -- -- Data.Express.Instances exports -- -- -- -- ** Typeclass instances as Exprs , reifyEq , reifyOrd , reifyEqOrd , reifyName , mkEq , mkOrd , mkOrdLessEqual , mkName , mkNameWith , isEq , isOrd , isEqOrd , isEqT , isOrdT , isEqOrdT , mkEquation , mkComparisonLE , mkComparisonLT , mkComparison , lookupComparison , listVarsWith , lookupName , lookupNames , validApps , findValidApp , preludeNameInstances ) where import Data.Express.Basic import Data.Express.Canon import Data.Express.Match import Data.Express.Name import Data.Express.Name.Derive import Data.Express.Express import Data.Express.Express.Derive import Data.Express.Instances