X-Git-Url: http://nitlanguage.org diff --git a/lib/pipeline.nit b/lib/pipeline.nit index 84e0a3e..0c422ed 100644 --- a/lib/pipeline.nit +++ b/lib/pipeline.nit @@ -99,7 +99,7 @@ redef interface Iterator[E] # # var i = [1,2,3,4,5].iterator # assert i.head(2).to_a == [1,2] - # i.to_a == [3,4,5] + # assert i.to_a == [3,4,5] fun head(length: Int): Iterator[E] do return new PipeHead[E](self, length) @@ -144,6 +144,58 @@ redef interface Iterator[E] do return new PipeSkipTail[E](self, length) end + + # Filter: reject items that does not meet some criteria. + # + # class IsEvenFunction + # super Function[Int, Bool] + # redef fun apply(i) do return i % 2 == 0 + # end + # assert [1,2,3,4,8].iterator.select(new IsEvenFunction).to_a == [2,4,8] + fun select(predicate: Function[E, Bool]): Iterator[E] + do + return new PipeSelect[E](self, predicate) + end +end + +# Interface that reify a function. +# Concrete subclasses must implements the `apply` method. +# +# This interface helps to manipulate function-like objects. +# +# The main usage it as a transformation; that takes an argument and produce a result. +# See `map` for example. +# +# Another usage is as a predicate, with `Function[E, Bool]`. +# See `Iterator::select` for example. +# +# Function with more than one argument can be reified with some uncurification. +# Eg. `Function[ARG1, Function[ARG2, RES]]`. +# +# NOTE: Nit is not a functionnal language, this class is a very basic way to +# simulate the reification of a simple function. +interface Function[FROM, TO] + # How an element is mapped to another one. + fun apply(e: FROM): TO is abstract + + # Filter: produce an iterator which each element is transformed. + # + # var i = [1,2,3].iterator + # assert fun_to_s.map(i).to_a == ["1", "2", "3"] + # + # Note: because there is no generic method in Nit (yet?), + # there is no way to have a better API. + # eg. with the Iterator as receiver and the function as argument. + # (see `Iterator::select`) + fun map(i: Iterator[FROM]): Iterator[TO] + do + return new PipeMap[FROM, TO](i, self) + end +end + +private class FunctionToS + super Function[Object, String] + redef fun apply(e) do return e.to_s end ### Specific private iterator classes @@ -315,3 +367,63 @@ private class PipeSkipTail[E] source.next end end + +private class PipeSelect[E] + super Iterator[E] + + var source: Iterator[E] + + var predicate: Function[E, Bool] + + init(source: Iterator[E], predicate: Function[E, Bool]) + do + self.source = source + self.predicate = predicate + + do_skip + end + + fun do_skip + do + while source.is_ok and not predicate.apply(source.item) do source.next + end + + redef fun is_ok do return source.is_ok + + redef fun item do return source.item + + redef fun next + do + source.next + do_skip + end +end + +private class PipeMap[E, F] + super Iterator[F] + + var source: Iterator[E] + var function: Function[E, F] + + var item_cache: nullable F = null + var item_cached = false + + redef fun is_ok do return source.is_ok + + redef fun item do + if item_cached then return item_cache + item_cache = function.apply(source.item) + item_cached = true + return item_cache + end + + redef fun next do + source.next + item_cached = false + end +end + +# Stateless singleton that reify to the `to_s` method. +# +# assert fun_to_s.apply(5) == "5" +fun fun_to_s: Function[Object, String] do return once new FunctionToS