/** * 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> ()