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 module is part of Conjure.
This defines the Conjurable
typeclass
and utilities involving it.
You are probably better off importing Conjure.
Synopsis
- type Reification1 = (Expr, Maybe Expr, Maybe [[Expr]], [String], Bool, Expr)
- type Reification = [Reification1] -> [Reification1]
- class (Typeable a, Name a) => Conjurable a where
- conjureArgumentHoles :: a -> [Expr]
- conjureEquality :: a -> Maybe Expr
- conjureTiers :: a -> Maybe [[Expr]]
- conjureSubTypes :: a -> Reification
- conjureIf :: a -> Expr
- conjureCases :: a -> [Expr]
- conjureArgumentCases :: a -> [[Expr]]
- conjureSize :: a -> Int
- conjureExpress :: a -> Expr -> Expr
- conjureEvaluate :: (Expr -> Expr) -> Int -> Defn -> Expr -> Maybe a
- conjureType :: Conjurable a => a -> Reification
- reifyTiers :: (Listable a, Show a, Typeable a) => a -> Maybe [[Expr]]
- reifyEquality :: (Eq a, Typeable a) => a -> Maybe Expr
- reifyExpress :: (Express a, Show a) => a -> Expr -> Expr
- conjureApplication :: Conjurable f => String -> f -> Expr
- conjureVarApplication :: Conjurable f => String -> f -> Expr
- conjurePats :: Conjurable f => [Expr] -> String -> f -> [[[Expr]]]
- conjureHoles :: Conjurable f => f -> [Expr]
- conjureTiersFor :: Conjurable f => f -> Expr -> [[Expr]]
- conjureAreEqual :: Conjurable f => f -> Int -> Expr -> Expr -> Bool
- conjureMkEquation :: Conjurable f => f -> Expr -> Expr -> Expr
- data A
- data B
- data C
- data D
- data E
- data F
- conjureIsDeconstructor :: Conjurable f => f -> Int -> Expr -> Bool
- conjureIsDeconstruction :: Conjurable f => f -> Int -> Expr -> Bool
- candidateDeconstructionsFrom :: Expr -> [Expr]
- candidateDeconstructionsFromHoled :: Expr -> [Expr]
- conjureIsUnbreakable :: Conjurable f => f -> Expr -> Bool
- conjureReification :: Conjurable a => a -> [Reification1]
- conjureReification1 :: Conjurable a => a -> Reification1
- conjureDynamicEq :: Conjurable f => f -> Dynamic
- cevaluate :: Conjurable f => Int -> Defn -> Maybe f
- ceval :: Conjurable f => Int -> f -> Defn -> f
- cevl :: Conjurable f => Int -> Defn -> f
- class Name a where
- class (Show a, Typeable a) => Express a where
Documentation
type Reification1 = (Expr, Maybe Expr, Maybe [[Expr]], [String], Bool, Expr) Source #
Single reification of some functions over a type as Expr
s.
This is a sixtuple, in order:
type Reification = [Reification1] -> [Reification1] Source #
A reification over a collection of types.
Represented as a transformation of a list to a list.
class (Typeable a, Name a) => Conjurable a where Source #
Class of Conjurable
types.
Functions are Conjurable
if all their arguments are Conjurable
, Listable
and Show
able.
For atomic types that are Listable
,
instances are defined as:
instance Conjurable Atomic where conjureTiers = reifyTiers
For atomic types that are both Listable
and Eq
,
instances are defined as:
instance Conjurable Atomic where conjureTiers = reifyTiers conjureEquality = reifyEquality
For types with subtypes, instances are defined as:
instance Conjurable Composite where conjureTiers = reifyTiers conjureEquality = reifyEquality conjureSubTypes x = conjureType y . conjureType z . conjureType w where (Composite ... y ... z ... w ...) = x
Above x
, y
, z
and w
are just proxies.
The Proxy
type was avoided for backwards compatibility.
Please see the source code of Conjure.Conjurable for more examples.
(cf. reifyTiers
, reifyEquality
, conjureType
)
conjureArgumentHoles :: a -> [Expr] Source #
conjureEquality :: a -> Maybe Expr Source #
Returns Just
the ==
function encoded as an Expr
when available
or Nothing
otherwise.
Use reifyEquality
when defining this.
conjureTiers :: a -> Maybe [[Expr]] Source #
Returns Just
tiers
of values encoded as Expr
s when possible
or Nothing
otherwise.
Use reifyTiers
when defining this.
conjureSubTypes :: a -> Reification Source #
conjureIf :: a -> Expr Source #
Returns an if-function encoded as an Expr
.
conjureCases :: a -> [Expr] Source #
Returns a top-level case breakdown.
conjureArgumentCases :: a -> [[Expr]] Source #
conjureSize :: a -> Int Source #
Returns the (recursive) size of the given value.
conjureExpress :: a -> Expr -> Expr Source #
Returns a function that deeply reencodes an expression when possible.
(id
when not available.)
Use reifyExpress
when defining this.
conjureEvaluate :: (Expr -> Expr) -> Int -> Defn -> Expr -> Maybe a Source #
Instances
conjureType :: Conjurable a => a -> Reification Source #
To be used in the implementation of conjureSubTypes
.
instance ... => Conjurable <Type> where ... conjureSubTypes x = conjureType (field1 x) . conjureType (field2 x) . ... . conjureType (fieldN x) ...
reifyTiers :: (Listable a, Show a, Typeable a) => a -> Maybe [[Expr]] Source #
Reifies equality to be used in a conjurable type.
This is to be used
in the definition of conjureTiers
of Conjurable
typeclass instances:
instance ... => Conjurable <Type> where ... conjureTiers = reifyTiers ...
reifyEquality :: (Eq a, Typeable a) => a -> Maybe Expr Source #
Reifies equality ==
in a Conjurable
type instance.
This is to be used
in the definition of conjureEquality
of Conjurable
typeclass instances:
instance ... => Conjurable <Type> where ... conjureEquality = reifyEquality ...
reifyExpress :: (Express a, Show a) => a -> Expr -> Expr Source #
Reifies the expr
function in a Conjurable
type instance.
This is to be used
in the definition of conjureExpress
of Conjurable
typeclass instances.
instance ... => Conjurable <Type> where ... conjureExpress = reifyExpress ...
conjureApplication :: Conjurable f => String -> f -> Expr Source #
Computes a complete application for the given function.
> conjureApplication "not" not not p :: Bool
> conjureApplication "+" ((+) :: Int -> Int -> Int) x + y :: Int
(cf. conjureVarApplication
)
conjureVarApplication :: Conjurable f => String -> f -> Expr Source #
Computes a complete application for a variable of the same type of the given function.
> conjureVarApplication "not" not not p :: Bool
> conjureVarApplication "+" ((+) :: Int -> Int -> Int) x + y :: Int
(cf. conjureApplication
)
conjurePats :: Conjurable f => [Expr] -> String -> f -> [[[Expr]]] Source #
Computes tiers of sets of patterns for the given function.
> conjurePats [zero] "f" (undefined :: Int -> Int) [[[f x :: Int]],[[f 0 :: Int,f x :: Int]]]
conjureHoles :: Conjurable f => f -> [Expr] Source #
Computes a list of holes encoded as Expr
s
from a Conjurable
functional value.
(cf. cjHoles
)
conjureTiersFor :: Conjurable f => f -> Expr -> [[Expr]] Source #
conjureAreEqual :: Conjurable f => f -> Int -> Expr -> Expr -> Bool Source #
Given a Conjurable
functional value,
computes a function that checks whether two Expr
s are equal
up to a given number of tests.
conjureMkEquation :: Conjurable f => f -> Expr -> Expr -> Expr Source #
Computes a function that makes an equation between two expressions.
Generic type A
.
Can be used to test polymorphic functions with a type variable
such as take
or sort
:
take :: Int -> [a] -> [a] sort :: Ord a => [a] -> [a]
by binding them to the following types:
take :: Int -> [A] -> [A] sort :: [A] -> [A]
This type is homomorphic to Nat6
, B
, C
, D
, E
and F
.
It is instance to several typeclasses so that it can be used to test functions with type contexts.
Instances
Bounded A | |
Enum A | |
Ix A | |
Num A | |
Read A | |
Integral A | |
Real A | |
Defined in Test.LeanCheck.Utils.Types toRational :: A -> Rational # | |
Show A | |
Conjurable A Source # | |
Defined in Conjure.Conjurable conjureArgumentHoles :: A -> [Expr] Source # conjureEquality :: A -> Maybe Expr Source # conjureTiers :: A -> Maybe [[Expr]] Source # conjureSubTypes :: A -> Reification Source # conjureIf :: A -> Expr Source # conjureCases :: A -> [Expr] Source # conjureArgumentCases :: A -> [[Expr]] Source # conjureSize :: A -> Int Source # conjureExpress :: A -> Expr -> Expr Source # conjureEvaluate :: (Expr -> Expr) -> Int -> Defn -> Expr -> Maybe A Source # | |
Express A Source # | |
Defined in Conjure.Expr | |
Name A Source # | |
Defined in Conjure.Conjurable | |
Eq A | |
Ord A | |
Listable A | |
Generic type B
.
Can be used to test polymorphic functions with two type variables
such as map
or foldr
:
map :: (a -> b) -> [a] -> [b] foldr :: (a -> b -> b) -> b -> [a] -> b
by binding them to the following types:
map :: (A -> B) -> [A] -> [B] foldr :: (A -> B -> B) -> B -> [A] -> B
Instances
Bounded B | |
Enum B | |
Ix B | |
Num B | |
Read B | |
Integral B | |
Real B | |
Defined in Test.LeanCheck.Utils.Types toRational :: B -> Rational # | |
Show B | |
Conjurable B Source # | |
Defined in Conjure.Conjurable conjureArgumentHoles :: B -> [Expr] Source # conjureEquality :: B -> Maybe Expr Source # conjureTiers :: B -> Maybe [[Expr]] Source # conjureSubTypes :: B -> Reification Source # conjureIf :: B -> Expr Source # conjureCases :: B -> [Expr] Source # conjureArgumentCases :: B -> [[Expr]] Source # conjureSize :: B -> Int Source # conjureExpress :: B -> Expr -> Expr Source # conjureEvaluate :: (Expr -> Expr) -> Int -> Defn -> Expr -> Maybe B Source # | |
Express B Source # | |
Defined in Conjure.Expr | |
Name B Source # | |
Defined in Conjure.Conjurable | |
Eq B | |
Ord B | |
Listable B | |
Generic type C
.
Can be used to test polymorphic functions with three type variables
such as uncurry
or zipWith
:
uncurry :: (a -> b -> c) -> (a, b) -> c zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
by binding them to the following types:
uncurry :: (A -> B -> C) -> (A, B) -> C zipWith :: (A -> B -> C) -> [A] -> [B] -> [C]
Instances
Bounded C | |
Enum C | |
Ix C | |
Num C | |
Read C | |
Integral C | |
Real C | |
Defined in Test.LeanCheck.Utils.Types toRational :: C -> Rational # | |
Show C | |
Conjurable C Source # | |
Defined in Conjure.Conjurable conjureArgumentHoles :: C -> [Expr] Source # conjureEquality :: C -> Maybe Expr Source # conjureTiers :: C -> Maybe [[Expr]] Source # conjureSubTypes :: C -> Reification Source # conjureIf :: C -> Expr Source # conjureCases :: C -> [Expr] Source # conjureArgumentCases :: C -> [[Expr]] Source # conjureSize :: C -> Int Source # conjureExpress :: C -> Expr -> Expr Source # conjureEvaluate :: (Expr -> Expr) -> Int -> Defn -> Expr -> Maybe C Source # | |
Express C Source # | |
Defined in Conjure.Expr | |
Name C Source # | |
Defined in Conjure.Conjurable | |
Eq C | |
Ord C | |
Listable C | |
Generic type D
.
Can be used to test polymorphic functions with four type variables.
Instances
Bounded D | |
Enum D | |
Ix D | |
Num D | |
Read D | |
Integral D | |
Real D | |
Defined in Test.LeanCheck.Utils.Types toRational :: D -> Rational # | |
Show D | |
Conjurable D Source # | |
Defined in Conjure.Conjurable conjureArgumentHoles :: D -> [Expr] Source # conjureEquality :: D -> Maybe Expr Source # conjureTiers :: D -> Maybe [[Expr]] Source # conjureSubTypes :: D -> Reification Source # conjureIf :: D -> Expr Source # conjureCases :: D -> [Expr] Source # conjureArgumentCases :: D -> [[Expr]] Source # conjureSize :: D -> Int Source # conjureExpress :: D -> Expr -> Expr Source # conjureEvaluate :: (Expr -> Expr) -> Int -> Defn -> Expr -> Maybe D Source # | |
Express D Source # | |
Defined in Conjure.Expr | |
Name D Source # | |
Defined in Conjure.Conjurable | |
Eq D | |
Ord D | |
Listable D | |
Generic type E
.
Can be used to test polymorphic functions with five type variables.
Instances
Bounded E | |
Enum E | |
Ix E | |
Num E | |
Read E | |
Integral E | |
Real E | |
Defined in Test.LeanCheck.Utils.Types toRational :: E -> Rational # | |
Show E | |
Conjurable E Source # | |
Defined in Conjure.Conjurable conjureArgumentHoles :: E -> [Expr] Source # conjureEquality :: E -> Maybe Expr Source # conjureTiers :: E -> Maybe [[Expr]] Source # conjureSubTypes :: E -> Reification Source # conjureIf :: E -> Expr Source # conjureCases :: E -> [Expr] Source # conjureArgumentCases :: E -> [[Expr]] Source # conjureSize :: E -> Int Source # conjureExpress :: E -> Expr -> Expr Source # conjureEvaluate :: (Expr -> Expr) -> Int -> Defn -> Expr -> Maybe E Source # | |
Express E Source # | |
Defined in Conjure.Expr | |
Name E Source # | |
Defined in Conjure.Conjurable | |
Eq E | |
Ord E | |
Listable E | |
Generic type F
.
Can be used to test polymorphic functions with five type variables.
Instances
Bounded F | |
Enum F | |
Ix F | |
Num F | |
Read F | |
Integral F | |
Real F | |
Defined in Test.LeanCheck.Utils.Types toRational :: F -> Rational # | |
Show F | |
Conjurable F Source # | |
Defined in Conjure.Conjurable conjureArgumentHoles :: F -> [Expr] Source # conjureEquality :: F -> Maybe Expr Source # conjureTiers :: F -> Maybe [[Expr]] Source # conjureSubTypes :: F -> Reification Source # conjureIf :: F -> Expr Source # conjureCases :: F -> [Expr] Source # conjureArgumentCases :: F -> [[Expr]] Source # conjureSize :: F -> Int Source # conjureExpress :: F -> Expr -> Expr Source # conjureEvaluate :: (Expr -> Expr) -> Int -> Defn -> Expr -> Maybe F Source # | |
Express F Source # | |
Defined in Conjure.Expr | |
Name F Source # | |
Defined in Conjure.Conjurable | |
Eq F | |
Ord F | |
Listable F | |
conjureIsDeconstructor :: Conjurable f => f -> Int -> Expr -> Bool Source #
Checks if an unary function encoded as an Expr
is a deconstructor.
(cf. conjureIsDeconstruction
)
conjureIsDeconstruction :: Conjurable f => f -> Int -> Expr -> Bool Source #
Checks if an expression is a deconstruction.
There should be a single hole
in the expression.
- The result does not increase the size for at least half the time.
- The result decreases in size for at least a third of the time.
(cf. conjureIsDeconstructor
)
candidateDeconstructionsFrom :: Expr -> [Expr] Source #
Compute candidate deconstructions from an Expr
.
This is used in the implementation of candidateDefnsC
followed by conjureIsDeconstruction
.
> candidateDeconstructionsFrom (xx `mod'` yy) [ _ `mod` y , x `mod` _ ]
To be constrasted with candidateDeconstructionsFromHoled
.
candidateDeconstructionsFromHoled :: Expr -> [Expr] Source #
Compute candidate deconstructions from an Expr
.
This is used in the implementation of candidateExprs
followed by conjureIsDeconstruction
.
This is similar to canonicalVariations
but always leaves a hole
of the same return type as the given expression.
> candidateDeconstructionsFrom (i_ `mod'` i_) [ _ `mod` x , x `mod` _ ]
To be contrasted with candidateDeconstructionsFrom
conjureIsUnbreakable :: Conjurable f => f -> Expr -> Bool Source #
Checks if an Expr
is of an unbreakable type.
conjureReification :: Conjurable a => a -> [Reification1] Source #
Conjures a list of Reification1
for a Conjurable
type, its subtypes and Bool
.
This is used in the implementation of
conjureHoles
,
conjureMkEquation
,
conjureAreEqual
,
conjureTiersFor
,
conjureIsDeconstructor
,
conjureNamesFor
,
conjureIsUnbreakable
,
etc.
conjureReification1 :: Conjurable a => a -> Reification1 Source #
Conjures a Reification1
for a Conjurable
type.
This is used in the implementation of conjureReification
.
conjureDynamicEq :: Conjurable f => f -> Dynamic Source #
ceval :: Conjurable f => Int -> f -> Defn -> f Source #
Evaluates a Defn
into a regular Haskell value
returning the given default value when there's a type mismatch.
The integer argument indicates the limit of recursive evaluations.
cevl :: Conjurable f => Int -> Defn -> f Source #
Evaluates a Defn
into a regular Haskell value
raising an error there's a type mismatch.
The integer argument indicates the limit of recursive evaluations.
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 |
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