/** * This module contains strategies for operating on tuples. * * In Stratego, tuples are a terms, separate from lists. * * @author Eelco Visser <visser@acm.org> * @author Karl Trygve Kalleberg <karltk@strategoxt.org> - documentation * * @see collection/list/common */ module collection/tuple/common imports collection/list/cons collection/tuple/cons collection/list/index collection/list/zip strategies /** Convert a tuple to a list. * * @type List(a) -> Tuple(a) */ TupleToList : "" # (xs) -> xs /** Convert a list to a tuple. * * @type Tuple(a) -> List(a) */ ListToTuple : xs -> "" # (xs) /** Retrieve the first element of a tuple. * * @type Tuple(a, xs...) -> a */ Fst : "" # ([x | xs]) -> x /** Retrieve the second element of a tuple. * * @type Tuple(a, b, xs...) -> b */ Snd : "" # ([x, y | xs]) -> y /** Retrieve the third element of a tuple. * * @type Tuple(a, b, c, xs...) -> c */ Third : "" # ([x, y, z | xs]) -> z /** Duplicate a term into a two-element tuple * * @type a -> Tuple(a, a) */ Dupl : x -> (x, x) /** Apply a pair of strategies, f and g, to a two-element tuple. The * strategy f will be applied to the first element, g to the second. * * @param f a -> a' * @param g b -> b' * @type Tuple(a, b) -> Tuple(a', b') */ split(f, g) = !(<f>, <g>) /** Apply a triple of strategies, f, g and h to a three-element tuple. * The strategy f will be applied to the first element, g to the second * and h to the third. * * @param f a -> a' * @param g b -> b' * @param h c -> c' * @type Tuple(a, b, c) -> Tuple(a', b', c') */ split3(f, g, h) = !(<f>, <g>, <h>) /** Swap two elements in a tuple. * * @type Tuple(a, b) -> Tuple(b, a) */ Swap : (x, y) -> (y, x) /** Retrieve the head of a tuple. * * @type Tuple(a) -> a * @see Fst */ Thd = Fst /** Retrieve the tail of a tuple. A new tuple with all elements except * the first will be returned. * * @type Tuple(a) -> Tuple(a) */ Ttl : "" # ([x | xs]) -> "" # (xs) /** Get the nth element of a tuple. The index must be smaller than the * number of elements in the tuple. * * @type (Int, Tuple(a)) -> a * @see index */ tindex = (id, ?""#(<id>)); index /** Predicate that checks if the supplied term is a tuple. * * @type Tuple(a) -?> Tuple(a) */ is-tuple = ?""#(_) /** Apply a strategy s to a swapped version of the supplied tuple. * The supplied tuple will be swapped, then is s applied. * * @param s Tuple(b,a) -> Tuple(b', a') * @type Tuple(a,b) -> Tuple(b', a') */ flip(s) = Swap; s /** Apply a strategy to each element of a tuple. This strategy maps * a strategy s over all elements in a tuple. * * @param s a -> b * @type Tuple(a) -> Tuple(b) */ tmap(s) = is-tuple; all(s) /** Concatenate the lists in a tuple of lists, using s as the * concatenation strategy. * * The concatenation strategy is asked to concatenate a two-element * tuple of lists and produce a list. Concatenation goes from right to * left. * * @param s Tuple(List(a), List(a)) -> List(a) * @type Tuple(List(a)) */ tconcat(s) = is-tuple; crush(![], s) /** Concatenate the lists in a tuple of lists, using s2 as the * concatenation strategy and s1 as the startup strategy. * * The strategy s1 is applied once initially to an empty list, and * can be used to create a custom tail on the resulting list. It can * also be used to concatenate into non-list types. * * The concatenation strategy s2 is asked to concatenate a * two-element tuple of lists and produce list. Concatenation goes * from right to left. * * Example: <tconcat'(!0, \([a],b)-><add> (a,b)\)> ([1],[2],[3]) => 6 * * @param s1 Nil -> b * @param s2 Tuple(List(a), b) -> b * @type Tuple(List(a)) * @see tconcat */ tconcat'(s1, s2) = is-tuple; crush(<s1> [], s2) /** Apply a s1 and s2 in a catamorphic way to reduce a tuple. * * s2 must be a catamorphism, i.e. it must be able to reduce the * elements of the tuple from right to left. * * This strategy is also named tfoldr, as it is equivalent to a * right-fold on tuples. * * @param s1 Nil -> b * @param s2 Tuple(a, b) -> b * @type Tuple(a) -> b * @see foldr */ tcata(s1, s2) = is-tuple; crush(s1, s2) /** * Fold a tuple from right to left using s2 as the folding strategy. * s1 is used to obtain the right-element (of type b) for s2. * * @param s1 Nil -> b * @param s2 Tuple(a, b) -> b * @type Tuple(a) -> b * @see tcata */ tfoldr(s1, s2) = tcata(s1, s2) /** Zip two tuples with s as the zipping strategy. * * Example: <tzip(add)> ((1,2,3),(5,4,3)) -> [6,6,6] * * @param s Tuple(a,b) -> c * @type Tuple(Tuple(a), Tuple(b)) -> c * @see zip */ tzip(s) = (TupleToList, TupleToList); zip(s) /** * @inc tuple-zip-test */ tuple-zip(s) = rec x(![<tmap(Hd); s> | <tmap(Tl); x>] <+ tmap([]); ![]) /** * @inc tuple-unzip-test */ tuple-unzip(s) = rec x(![<map(Thd); s> | <map(Ttl); x>] <+ map(()); ![]) ; !"" #(<id>)