express 0.1.1 → 0.1.2
raw patch · 9 files changed
+244/−50 lines, 9 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
+ Data.Express.Express: (-:) :: a -> a -> a
+ Data.Express.Express: (->:) :: (a -> b) -> b -> a -> b
+ Data.Express.Express: (->>:) :: (a -> b -> c) -> c -> a -> b -> c
+ Data.Express.Express: (->>>:) :: (a -> b -> c -> d) -> d -> a -> b -> c -> d
+ Data.Express.Express: (->>>>:) :: (a -> b -> c -> d -> e) -> e -> a -> b -> c -> d -> e
+ Data.Express.Express: (->>>>>:) :: (a -> b -> c -> d -> e -> f) -> f -> a -> b -> c -> d -> e -> f
+ Data.Express.Express: (->>>>>>:) :: (a -> b -> c -> d -> e -> f -> g) -> g -> a -> b -> c -> d -> e -> f -> g
+ Data.Express.Express: (->>>>>>>:) :: (a -> b -> c -> d -> e -> f -> g -> h) -> h -> a -> b -> c -> d -> e -> f -> g -> h
+ Data.Express.Express: (->>>>>>>>:) :: (a -> b -> c -> d -> e -> f -> g -> h -> i) -> i -> a -> b -> c -> d -> e -> f -> g -> h -> i
+ Data.Express.Express: (->>>>>>>>>:) :: (a -> b -> c -> d -> e -> f -> g -> h -> i -> j) -> j -> a -> b -> c -> d -> e -> f -> g -> h -> i -> j
+ Data.Express.Express: (->>>>>>>>>>:) :: (a -> b -> c -> d -> e -> f -> g -> h -> i -> j -> k) -> k -> a -> b -> c -> d -> e -> f -> g -> h -> i -> j -> k
+ Data.Express.Express: (->>>>>>>>>>>:) :: (a -> b -> c -> d -> e -> f -> g -> h -> i -> j -> k -> l) -> l -> a -> b -> c -> d -> e -> f -> g -> h -> i -> j -> k -> l
+ Data.Express.Express: (->>>>>>>>>>>>:) :: (a -> b -> c -> d -> e -> f -> g -> h -> i -> j -> k -> l -> m) -> m -> a -> b -> c -> d -> e -> f -> g -> h -> i -> j -> k -> l -> m
+ Data.Express.Express: infixl 1 ->>>>>>>>>>>>:
+ Data.Express.Utils.TH: (|++|) :: DecsQ -> DecsQ -> DecsQ
Files
- README.md +51/−1
- express.cabal +2/−2
- src/Data/Express.hs +43/−1
- src/Data/Express/Core.hs +57/−17
- src/Data/Express/Express.hs +45/−26
- src/Data/Express/Express/Derive.hs +33/−2
- src/Data/Express/Instances.hs +8/−0
- src/Data/Express/Utils/TH.hs +4/−0
- test/Test.hs +1/−1
README.md view
@@ -30,12 +30,61 @@ $ cabal install express +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++ > let one = val (1 :: Int)+ > :t one+ one :: Expr+ > print one+ 1 :: Int++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`] and [`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 1: heterogeneous lists ------------------------------ Like with [`Data.Dynamic`], we can use Express to create heterogeneous lists. -For types that are [`Show`] instances, we can use [`val`] to encode values as [`Expr`]s. Here, we use applications of [`val`] to create a heterogeneous list: > let xs = [val False, val True, val (1::Int), val (2::Int), val (3::Integer), val "123"]@@ -292,6 +341,7 @@ [`Expr`]: https://hackage.haskell.org/package/express/docs/Data-Express.html#t:val [`val`]: https://hackage.haskell.org/package/express/docs/Data-Express.html#v:val [`evaluate`]: https://hackage.haskell.org/package/express/docs/Data-Express.html#v:evaluate+[`:$`]: https://hackage.haskell.org/package/express-0.1.1/docs/Data-Express.html#v::-36- [`$$`]: https://hackage.haskell.org/package/express/docs/Data-Express.html#v:-36--36- [`Show`]: https://hackage.haskell.org/package/base/docs/Prelude.html#t:Show [`Data.Dynamic`]: https://hackage.haskell.org/package/base/docs/Data-Dynamic.html
express.cabal view
@@ -1,6 +1,6 @@ -- Cabal file for express name: express-version: 0.1.1+version: 0.1.2 synopsis: Dynamically-typed expressions involving applications and variables. description: Express is a library for manipulating dynamically typed Haskell expressions.@@ -57,7 +57,7 @@ source-repository this type: git location: https://github.com/rudymatela/express- tag: v0.1.1+ tag: v0.1.2 library exposed-modules: Data.Express
src/Data/Express.hs view
@@ -12,6 +12,48 @@ -- 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: --@@ -39,7 +81,7 @@ -- > > mapMaybe evaluate xs :: [String] -- > ["123"] ----- If define an heterogeneous list of functions encoded as 'Expr's:+-- 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
src/Data/Express/Core.hs view
@@ -825,26 +825,30 @@ -- > > values (xx -+- yy) -- > [ (+) :: Int -> Int -> Int -- > , x :: Int--- > , y :: Int ]+-- > , y :: Int+-- > ] -- -- > > values (xx -+- (yy -+- zz)) -- > [ (+) :: Int -> Int -> Int -- > , x :: Int -- > , (+) :: Int -> Int -> Int -- > , y :: Int--- > , z :: Int ]+-- > , z :: Int+-- > ] -- -- > > values (zero -+- (one -*- two)) -- > [ (+) :: Int -> Int -> Int -- > , 0 :: Int -- > , (*) :: Int -> Int -> Int -- > , 1 :: Int--- > , 2 :: Int ]+-- > , 2 :: Int+-- > ] -- -- > > values (pp -&&- true) -- > [ (&&) :: Bool -> Bool -> Bool -- > , p :: Bool--- > , True :: Bool ]+-- > , True :: Bool+-- > ] values :: Expr -> [Expr] values e = v e [] where@@ -859,24 +863,28 @@ -- > > nubValues (xx -+- yy) -- > [ x :: Int -- > , y :: Int--- > , (+) :: Int -> Int -> Int ]+-- > , (+) :: Int -> Int -> Int+-- ] -- -- > > nubValues (xx -+- (yy -+- zz)) -- > [ x :: Int -- > , y :: Int -- > , z :: Int--- > , (+) :: Int -> Int -> Int ]+-- > , (+) :: Int -> Int -> Int+-- > ] -- -- > > nubValues (zero -+- (one -*- two)) -- > [ 0 :: Int -- > , 1 :: Int -- > , 2 :: Int -- > , (*) :: Int -> Int -> Int--- > , (+) :: Int -> Int -> Int ]+-- > , (+) :: Int -> Int -> Int+-- > ] -- -- > > nubValues (pp -&&- pp) -- > [ p :: Bool--- > , (&&) :: Bool -> Bool -> Bool ]+-- > , (&&) :: Bool -> Bool -> Bool+-- > ] nubValues :: Expr -> [Expr] nubValues = v where@@ -892,18 +900,21 @@ -- -- > > consts (xx -+- (yy -+- zz)) -- > [ (+) :: Int -> Int -> Int--- > , (+) :: Int -> Int -> Int ]+-- > , (+) :: Int -> Int -> Int+-- > ] -- -- > > consts (zero -+- (one -*- two)) -- > [ (+) :: Int -> Int -> Int -- > , 0 :: Int -- > , (*) :: Int -> Int -> Int -- > , 1 :: Int--- > , 2 :: Int ]+-- > , 2 :: Int+-- > ] -- -- > > consts (pp -&&- true) -- > [ (&&) :: Bool -> Bool -> Bool--- > , True :: Bool ]+-- > , True :: Bool+-- > ] consts :: Expr -> [Expr] consts = filter isConst . values @@ -919,7 +930,8 @@ -- -- > > nubConsts (pp -&&- true) -- > [ True :: Bool--- > , (&&) :: Bool -> Bool -> Bool ]+-- > , (&&) :: Bool -> Bool -> Bool+-- > ] nubConsts :: Expr -> [Expr] nubConsts = c where@@ -932,12 +944,14 @@ -- -- > > vars (xx -+- yy) -- > [ x :: Int--- > , y :: Int ]+-- > , y :: Int+-- > ] -- -- > > vars (xx -+- (yy -+- xx)) -- > [ x :: Int -- > , y :: Int--- > , x :: Int ]+-- > , x :: Int+-- > ] -- -- > > vars (zero -+- (one -*- two)) -- > []@@ -953,11 +967,13 @@ -- -- > > nubVars (yy -+- xx) -- > [ x :: Int--- > , y :: Int ]+-- > , y :: Int+-- > ] -- -- > > nubVars (xx -+- (yy -+- xx)) -- > [ x :: Int--- > , y :: Int ]+-- > , y :: Int+-- > ] -- -- > > nubVars (zero -+- (one -*- two)) -- > []@@ -974,7 +990,7 @@ -- Return the arity of the given expression, -- i.e. the number of arguments that its type takes. ----- > > arity (val 0)+-- > > arity (val (0::Int)) -- > 0 -- -- > > arity (val False)@@ -995,6 +1011,12 @@ -- 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 --@@ -1014,6 +1036,14 @@ -- 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 --@@ -1037,6 +1067,16 @@ -- 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
src/Data/Express/Express.hs view
@@ -6,7 +6,23 @@ -- -- Defines the 'Express' type class. {-# LANGUAGE CPP #-}-module Data.Express.Express (Express (..)) where+module Data.Express.Express+ ( Express (..)+ , (-:)+ , (->:)+ , (->>:)+ , (->>>:)+ , (->>>>:)+ , (->>>>>:)+ , (->>>>>>:)+ , (->>>>>>>:)+ , (->>>>>>>>:)+ , (->>>>>>>>>:)+ , (->>>>>>>>>>:)+ , (->>>>>>>>>>>:)+ , (->>>>>>>>>>>>:)+ )+where import Data.Express.Core import Data.Typeable@@ -41,7 +57,7 @@ -- > 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 @ class Typeable a => Express a where@@ -162,81 +178,84 @@ -- type binding utilities -- +-- | Type restricted version of const+-- that forces its first argument+-- to have the same type as the second.+--+-- > value -: (undefined :: Ty) = value :: Ty (-:) :: a -> a -> a (-:) = asTypeOf -- const infixl 1 -: -(-:>) :: (a -> b) -> a -> (a -> b)-(-:>) = const-infixl 1 -:>-+-- | Type restricted version of const+-- that forces the result of its first argument+-- to have the same type as the second.+--+-- > f ->: (undefined :: Ty) = f :: a -> Ty (->:) :: (a -> b) -> b -> (a -> b) (->:) = const infixl 1 ->: -(->:>) :: (a -> b -> c) -> b -> (a -> b -> c)-(->:>) = const-infixl 1 ->:>-+-- | Type restricted version of const+-- that forces the result of the result of its first argument+-- to have the same type as the second.+--+-- > f ->>: (undefined :: Ty) = f :: a -> b -> Ty (->>:) :: (a -> b -> c) -> c -> (a -> b -> c) (->>:) = const infixl 1 ->>: -(->>:>) :: (a -> b -> c -> d) -> c -> (a -> b -> c -> d)-(->>:>) = const-infixl 1 ->>:>-+-- | Type restricted version of const+-- that forces the result of the result of the result of its first argument+-- to have the same type as the second. (->>>:) :: (a -> b -> c -> d) -> d -> (a -> b -> c -> d) (->>>:) = const infixl 1 ->>>: -(->>>:>) :: (a -> b -> c -> d -> e) -> d -> (a -> b -> c -> d -> e)-(->>>:>) = const-infixl 1 ->>>:>-+-- | Forces the result type of a 4-argument function. (->>>>:) :: (a -> b -> c -> d -> e) -> e -> (a -> b -> c -> d -> e) (->>>>:) = const infixl 1 ->>>>: -(->>>>:>) :: (a -> b -> c -> d -> e -> f) -> e -> (a -> b -> c -> d -> e -> f)-(->>>>:>) = const-infixl 1 ->>>>:>-+-- | Forces the result type of a 5-argument function. (->>>>>:) :: (a -> b -> c -> d -> e -> f) -> f -> (a -> b -> c -> d -> e -> f) (->>>>>:) = const infixl 1 ->>>>>: -(->>>>>:>) :: (a->b->c->d->e->f->g) -> f -> (a->b->c->d->e->f->g)-(->>>>>:>) = const-infixl 1 ->>>>>:>-+-- | Forces the result type of a 6-argument function. (->>>>>>:) :: (a->b->c->d->e->f->g) -> g -> (a->b->c->d->e->f->g) (->>>>>>:) = const infixl 1 ->>>>>>: +-- | Forces the result type of a 7-argument function. (->>>>>>>:) :: (a->b->c->d->e->f->g->h) -> h -> (a->b->c->d->e->f->g->h) (->>>>>>>:) = const infixl 1 ->>>>>>>: +-- | Forces the result type of a 8-argument function. (->>>>>>>>:) :: (a->b->c->d->e->f->g->h->i) -> i -> (a->b->c->d->e->f->g->h->i) (->>>>>>>>:) = const infixl 1 ->>>>>>>>: +-- | Forces the result type of a 9-argument function. (->>>>>>>>>:) :: (a->b->c->d->e->f->g->h->i->j) -> j -> (a->b->c->d->e->f->g->h->i->j) (->>>>>>>>>:) = const infixl 1 ->>>>>>>>>: +-- | Forces the result type of a 10-argument function. (->>>>>>>>>>:) :: (a->b->c->d->e->f->g->h->i->j->k) -> k -> (a->b->c->d->e->f->g->h->i->j->k) (->>>>>>>>>>:) = const infixl 1 ->>>>>>>>>>: +-- | Forces the result type of a 11-argument function. (->>>>>>>>>>>:) :: (a->b->c->d->e->f->g->h->i->j->k->l) -> l -> (a->b->c->d->e->f->g->h->i->j->k->l) (->>>>>>>>>>>:) = const infixl 1 ->>>>>>>>>>>: +-- | Forces the result type of a 12-argument function. (->>>>>>>>>>>>:) :: (a->b->c->d->e->f->g->h->i->j->k->l->m) -> m -> (a->b->c->d->e->f->g->h->i->j->k->l->m) (->>>>>>>>>>>>:) = const
src/Data/Express/Express/Derive.hs view
@@ -20,10 +20,15 @@ import Data.Char import Data.List import Data.Express.Utils.TH+import Data.Express.Utils.List+import Data.Express.Utils.String -- | Derives an 'Express' instance for the given type 'Name'. -- -- This function needs the @TemplateHaskell@ extension.+--+-- If '-:', '->:', '->>:', '->>>:', ... are not in scope,+-- this will derive them as well. deriveExpress :: Name -> DecsQ deriveExpress = deriveWhenNeededOrWarn ''Express reallyDeriveExpress @@ -52,8 +57,9 @@ , v <- vs] cs <- typeConstructorsArgNames t asName <- newName "x"+ let withTheReturnTypeOfs = deriveWithTheReturnTypeOfs $ [length ns | (_,ns) <- cs] let generalizableExpr = mergeIFns $ foldr1 mergeI- [ do retTypeOf <- lookupValN $ "-" ++ replicate (length ns) '>' ++ ":"+ [ do let retTypeOf = mkName $ "-" ++ replicate (length ns) '>' ++ ":" let exprs = [[| expr $(varE n) |] | n <- ns] let conex = [| $(varE retTypeOf) $(conE c) $(varE asName) |] let root = [| value $(stringE $ showJustName c) $(conex) |]@@ -62,9 +68,34 @@ expr $(asP asName $ conP c (map varP ns)) = $rhs |] | (c,ns) <- cs ]- cxt |=>| generalizableExpr+ withTheReturnTypeOfs |++| (cxt |=>| generalizableExpr) -- Not only really derive Express instances, -- but cascade through argument types. reallyDeriveExpressCascading :: Name -> DecsQ reallyDeriveExpressCascading = reallyDeriveCascading ''Express reallyDeriveExpress++deriveWithTheReturnTypeOfs :: [Int] -> DecsQ+deriveWithTheReturnTypeOfs =+ fmap concat . mapM deriveWithTheReturnTypeOf . nubSort++deriveWithTheReturnTypeOf :: Int -> DecsQ+deriveWithTheReturnTypeOf n = do+ mf <- lookupValueName name+ case mf of+ Nothing -> reallyDeriveWithTheReturnTypeOf n+ Just _ -> return []+ where+ name = "-" ++ replicate n '>' ++ ":"++reallyDeriveWithTheReturnTypeOf :: Int -> DecsQ+reallyDeriveWithTheReturnTypeOf n = do+ td <- sigD name theT+ vd <- [d| $(varP name) = const |]+ return $ td:vd+ where+ theT = [t| $(theFunT) -> $(last vars) -> $(theFunT) |]+ theFunT = foldr1 funT vars+ funT t1 t2 = [t| $(t1) -> $(t2) |]+ vars = map (varT . mkName) . take (n+1) . primeCycle $ map (:"") ['a'..'z']+ name = mkName $ "-" ++ replicate n '>' ++ ":"
src/Data/Express/Instances.hs view
@@ -5,6 +5,14 @@ -- Maintainer : Rudy Matela <rudy@matela.com.br> -- -- Defines utilities do deal with instances of typeclasses+--+-- Functions provided by this module store the set of instances as a simple+-- Haskell list. When storing only a few instances this should be fine in+-- terms of performance.+--+-- If you plan to store hundreds or thousands of instances,+-- we recommend implementing different versions that use+-- a more efficient Set/Map storage. module Data.Express.Instances ( reifyEq , reifyOrd
src/Data/Express/Utils/TH.hs view
@@ -27,6 +27,7 @@ , showJustName , typeConstructorsArgNames , (|=>|)+ , (|++|) , whereI , module Language.Haskell.TH )@@ -229,6 +230,9 @@ where ac (InstanceD o c ts ds) c' = InstanceD o (c++c') ts ds ac d _ = d #endif++(|++|) :: DecsQ -> DecsQ -> DecsQ+(|++|) = liftM2 (++) mergeIFns :: DecsQ -> DecsQ mergeIFns qds = do ds <- qds
test/Test.hs view
@@ -9,8 +9,8 @@ -- It should never be exported in @ express.cabal @. module Test ( module Test.LeanCheck- , module Test.LeanCheck.Utils , module Test.LeanCheck.Derive+ , module Test.LeanCheck.Utils , module Data.Express.Fixtures , module Data.Express.Utils.List , module Data.Express.Utils.Typeable