Open Vaguery opened 6 years ago
This will probably lead to some refactoring of the DSL, which is a good thing.
Consider bringing predicate functions up into a collection associated with each type, rather than being hard-coded inside the DSL definition. For instance, :scalar-≤
should probably invoke the :scalar
type's ≤
predicate in its DSL definition. That way, the :predicate
object has access to it as well. Also faster.
The comparable
aspect might insert these predicates into the type.
The
:predicate
type is a tuple of:boolean
For example, here are some one-argument
:predicate
definitions:Predicate(:scalar, #(% > 9.3))
Predicate(:string, #(contains? % "foo"))
Predicate(:string, #(= % "bar"))
Predicate(:scalars, #(contains-permutation-pattern? % [2,1,3,5,4])
Predicate(:matrix, #(multiplication-compatible? % Matrix[[1 2 3],[4 5 6]])
Predicate(:set, #(nonempty-intersection? % #{7, "a", \g, [4 5]))
Predicate(:complex, #(dominates? % Complex(8,2))
Predicate(:vector, mixed-type?)
Here are some two-argument
:predicates
:Predicate(:scalar, <=)
Predicate(:string, contains-with-gaps?)
Predicate(:interval, overlaps?)
Predicate(:code, contains?)
Making
:predicate
objects:predicate-fromtemplate
pops top:predicate
and makes a new one of the same type (and function) from the top item on the appropriate stackFor "predicatable" types:
:X->equalitypredicate1
pops the top:X
and creates a newPredicate(:X, #(= % [item]))
:X->equalitypredicate2
creates a newPredicate(:X, equal?)
:X->lessthanpredicate1
pops the top:X
(call it A) and creates a newPredicate(:X, #(< % A))
:X-> lessthanpredicate2
creates a newPredicate(:X, lessthan?)
:X->greaterthanpredicate1
pops the top:X
(call it A) and creates a newPredicate(:X, #(> % A))
:X-> greaterthanpredicate2
creates a newPredicate(:X, greaterthan?)
:X->contains1
pops the top:X
(call it A) and creates a newPredicate(:X, #(contains? % A))
:X-> contains2
creates a newPredicate(:X, contains?)
:X->contained1
pops the top:X
(call it A) and creates a newPredicate(:X, #(contained-in? % A))
:X-> contained2
creates a newPredicate(:X, contained-in?)
Some special instructions for particular types are feasible (but not included), as well, such as:
:string->close?
pops a:string
A and:scalar
B and creates a newPredicate(:string, #(< (edit-distance % A) B)
What they do
Whenever these instructions fire, the top predicate may want one or two arguments. By convention a
:boolean
will be used to determine whether a constant will be in the first position or second if there are two arguments in the predicate.:predicate-apply
pops the one or two items of the predicate's type, and returns the:boolean
result:predicate-map
:predicate
, applies the predicate to every item on the top item of the appropriate vectorized type, returning a:booleans
vector of the same length:predicate
, pops one item from vector, one from items, one from:boolean
; if:boolean
istrue
, it uses the item in the first position in each comparison, iffalse
, it uses it in the second position:predicate-split
:predicate
, takes the top item from the appropriate vectorized stack, and returns two vectors of items that match and those that don't:predicate
, pops one item from vector, one from items, one from:boolean
; based on:boolean
it puts the item in the first or second positions:predicate-first
takes the top vector of that type, returns the first item matching the predicate (if any); for 2-arg version, see above:predicate-next
takes the top vector of that type, returns the first item matching the predicate (if any) AND the reduced vector; for 2-arg version, see above:predicate-hoist
takes the top vector of that type, pushes the same vector with the first matching item brought to the front; for 2-arg version, see above:predicate-remove
takes top vector, returns new vector with only failing items; for 2-arg version, see above:predicate-keep
takes top vector, returns new vector with only passing items; for 2-arg version, see aboveFancier stuff:
:predicate-applyeach
pops a:predicate
:predicate-apply
:wrap-vectors? true
works like R, cycling the items of the shorter vector to get enough items to compare; for example if these are:scalars
, and args are[1 2 3 4 5]
&[6 7]
, we produce a result[[1 v 6] [2 v 7] [3 v 6] [4 v 7] [5 v 6]]
:wrap-vectors? false
terminates when the shorter vector runs out of items; for example if these are:scalars
, and args are[1 2 3 4 5]
&[6 7]
, we produce a result[[1 v 6] [2 v 7]]
:predicate-mapeach
pops a:predicate
:predicate-map
:wrap-vectors? true
works like R, cycling the items of the shorter vector to get enough items to compare:wrap-vectors? false
terminates when the shorter vector runs out of items(and so on, by extension)