express-1.0.14: src/Data/Express.hs
-- |
-- 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