+
+ # 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
+
+# Wraps an iterator to skip nulls.
+#
+# ~~~nit
+# var i: Iterator[Int]
+#
+# i = new NullSkipper[Int]([null, 1, null, 2, null: nullable Int].iterator)
+# assert i.to_a == [1, 2]
+#
+# i = new NullSkipper[Int]([1, null, 2, 3: nullable Int].iterator)
+# assert i.to_a == [1, 2, 3]
+# ~~~
+class NullSkipper[E: Object]
+ super Iterator[E]
+
+ # The inner iterator.
+ var inner: Iterator[nullable E]
+
+ redef fun finish do inner.finish
+
+ redef fun is_ok do
+ skip_nulls
+ return inner.is_ok
+ end
+
+ redef fun item do
+ skip_nulls
+ return inner.item.as(E)
+ end
+
+ redef fun next do
+ inner.next
+ skip_nulls
+ end
+
+ private fun skip_nulls do
+ while inner.is_ok and inner.item == null do inner.next
+ 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