/**
* Conditionals
*/
module strategy/conditional
imports strategy/general/option
strategies // Equality
/**
* Tests whether two terms are equal.
*/
eq =
?(x, x)
/**
* Tests whether two terms are equal.
*/
equal =
?(x, x)
/**
* Tests whether current term is equal to argument term.
*/
equal(|x) =
?x
/**
* Tests whether two argument terms are equal to each other.
*/
equal(|x, y) =
where(!x => y)
strategies // Control-flow combinators
/**
* try(s) tries to apply s to the current term, but
* returns it unchanged (and succeeds) when s fails.
*/
try(s) =
s <+ id
if(c, b) =
c < b + id
if(c, b1, b2) =
c < b1 + b2
/**
* Apply restoring action 'rest' if s fails, and then fail.
*
* Typically useful if s performs side effects that should be
* restored/undone in case s fails.
*/
restore(s, rest) =
s <+ (rest; fail)
/**
* Apply restoring action 'rest' after s terminates, and preserve
* success/failure behaviour of s.
*
* Typically useful if s performs side effects that should be
* restored always, e.g., when maintaining scope information.
*/
restore-always(s, rest) =
s < rest + (rest; fail)
/**
* Applies s followed by f whether s failed or not.
*
* @result <s> input
* @fail s or f failed (consider try(f))
* @type a -> b, (a or b) -> _ :: a -> b
*/
finally(s, f) =
s < where(f) + (where(f); fail)
strategies // Boolean combinators
/**
* true is a synonym for id.
*/
true =
id
/**
* false is a synonym for id.
*/
false =
fail
/**
* ior(s1, s2) implements 'inclusive or', that is, the
* inclusive choice of s1 and s2. It first tries s1, if
* that fails it applies s2 (just like s1 <+ s2). However,
* when s1 succeeds it also tries to apply s2.
*
* The results of the transformations are returned.
*/
ior(s1, s2) =
(s1; try(s2)) <+ s2
/**
* or(s1, s2) is similar to ior(s1,s2), but the application
* of the strategies is only tested.
*/
or(s1, s2) =
if s1 then try(test(s2)) else test(s2) end
/**
* and(s1, s2) applies s1 and s2 to the current
* term and succeeds if both succeed. s2 will always
* be applied, i.e., and is *not* a short-circuit
* operator
*/
and(s1, s2) =
if s1 then test(s2) else test(s2); fail end
strategies
// a -> b :: a -> Option(b)
maybe(s) = !Some(<s>) <+ !None()
// a -> b, () -> b :: Option(a) -> b
maybe(s1, s2) : Some(a) -> <s1> a
maybe(s1, s2) : None() -> <s2> ()