Procházet zdrojové kódy

added Lambda specification

Simon Krajewski před 12 roky
rodič
revize
774ac753bd
2 změnil soubory, kde provedl 175 přidání a 16 odebrání
  1. 70 16
      std/Lambda.hx
  2. 105 0
      tests/unit/unitstd/Lambda.unit.hx

+ 70 - 16
std/Lambda.hx

@@ -19,14 +19,25 @@
  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  * DEALINGS IN THE SOFTWARE.
  */
+
 /**
-	The [Lambda] class is a collection of functional methods in order to
-	use functional-style programming with haXe.
+	The [Lambda] class is a collection of methods to support functional
+	programming. It is ideally used with 'using Lambda' and then acts as an
+	extension to Iterable types.
+	
+	On static platforms, working with the Iterable structure might be slower
+	than performing the operations directly on known types, such as Array and
+	List.
+	
+	If the first argument to any of the methods is null, the result is
+	unspecified.
 **/
 class Lambda {
 
 	/**
-		Creates an [Array] from an [Iterable]
+		Creates an Array from Iterable [it].
+		
+		If [it] is an Array, this function returns a copy of it.
 	**/
 	public static function array<A>( it : Iterable<A> ) : Array<A> {
 		var a = new Array<A>();
@@ -36,7 +47,9 @@ class Lambda {
 	}
 
 	/**
-		Creates a [List] from an [Iterable]
+		Creates a List form Iterable [it].
+		
+		If [it] is a List, this function returns a copy of it.
 	**/
 	public static function list<A>( it : Iterable<A> ) : List<A> {
 		var l = new List<A>();
@@ -46,8 +59,11 @@ class Lambda {
 	}
 
 	/**
-		Creates a new [Iterable] by appling the function 'f' to all
-		elements of the iterator 'it'.
+		Creates a new List by applying function [f] to all elements of [it].
+		
+		The order of elements is preserved.
+		
+		If [f] is null, the result is unspecified.
 	**/
 	public static function map<A,B>( it : Iterable<A>, f : A -> B ) : List<B> {
 		var l = new List<B>();
@@ -57,7 +73,11 @@ class Lambda {
 	}
 
 	/**
-		Similar to [map], but also pass an index for each item iterated.
+		Similar to map, but also passes the index of each element to [f].
+		
+		The order of elements is preserved.
+		
+		If [f] is null, the result is unspecified.
 	**/
 	public static function mapi<A,B>( it : Iterable<A>, f : Int -> A -> B ) : List<B> {
 		var l = new List<B>();
@@ -73,6 +93,8 @@ class Lambda {
 		a third parameter a function that performs the comparison.
 		That function must take as arguments the two items to
 		compare and returns a boolean value.
+		
+		TODO
 	**/
 	public static function has<A>( it : Iterable<A>, elt : A, ?cmp : A -> A -> Bool ) : Bool {
 		if( cmp == null ) {
@@ -88,7 +110,14 @@ class Lambda {
 	}
 
 	/**
-		Tells if at least one element of the iterable is found by using the specific function.
+		Tells if [it] contains an element for which [f] is true.
+		
+		This function returns true as soon as an element is found for which a
+		call to [f] returns true.
+		
+		If no such element is found, the result is false.
+		
+		If [f] is null, the result is unspecified.
 	**/
 	public static function exists<A>( it : Iterable<A>, f : A -> Bool ) {
 		for( x in it )
@@ -98,7 +127,16 @@ class Lambda {
 	}
 
 	/**
-		Tells if all elements of the iterable have the specified property defined by [f].
+		Tells if [f] is true for all elements of [it].
+		
+		This function returns false as soon as an element is found for which a
+		call to [f] returns false.
+		
+		If no such element is found, the result is true.
+		
+		In particular, this function always returns true if [it] is empty.
+		
+		If [f] is null, the result is unspecified.
 	**/
 	public static function foreach<A>( it : Iterable<A>, f : A -> Bool ) {
 		for( x in it )
@@ -108,7 +146,9 @@ class Lambda {
 	}
 
 	/**
-		Call the function 'f' on all elements of the [Iterable] 'it'.
+		Calls [f] on all elements of [it], in order.
+		
+		If [f] is null, the result is unspecified.
 	**/
 	public static function iter<A>( it : Iterable<A>, f : A -> Void ) {
 		for( x in it )
@@ -116,7 +156,12 @@ class Lambda {
 	}
 
 	/**
-		Return the list of elements matching the function 'f'
+		Returns a List containing those elements of [it] for which [f] returned
+		true.
+		
+		If [it] is empty, the result is the empty List even if [f] is null.
+		
+		Otherwise if [f] is null, the result is unspecified.
 	**/
 	public static function filter<A>( it : Iterable<A>, f : A -> Bool ) {
 		var l = new List<A>();
@@ -136,7 +181,10 @@ class Lambda {
 	}
 
 	/**
-		Count the number of elements in an [Iterable] having [pred] returning true.
+		Returns the number of elements in [it] for which [pred] is true, or the
+		total number of elements in [it] if [pred] is null.
+		
+		This function traverses all elements.
 	**/
 	public static function count<A>( it : Iterable<A>, ?pred : A -> Bool ) {
 		var n = 0;
@@ -151,15 +199,18 @@ class Lambda {
 	}
 
 	/**
-		Tells if an iterable does not contain any element.
+		Tells if Iterable [it] does not contain any element.
 	**/
 	public static function empty( it : Iterable<Dynamic> ) : Bool {
 		return !it.iterator().hasNext();
 	}
 
 	/**
-		Returns the index of the item in the given Iterable, depending on the order of the Iterator.
-		Returns -1 if the item was not found.
+		Returns the index of the first element [v] within Iterable [it].
+		
+		This function uses operator [==] to check for equality.
+		
+		If [v] does not exist in [it], the result is -1.
 	**/
 	public static function indexOf<T>( it : Iterable<T>, v : T ) : Int {
 		var i = 0;
@@ -172,7 +223,10 @@ class Lambda {
 	}
 
 	/**
-		Returns a list containing all items of 'a' followed by all items of 'b'
+		Returns a new List containing all elements of Iterable [a] followed by
+		all elements of Iterable [b].
+		
+		If [a] or [b] are null, the result is unspecified.
 	**/
 	public static function concat<T>( a : Iterable<T>, b : Iterable<T> ) : List<T> {
 		var l = new List();

+ 105 - 0
tests/unit/unitstd/Lambda.unit.hx

@@ -0,0 +1,105 @@
+function name(o:Dynamic) return Type.getClassName(Type.getClass(o));
+// array
+var a = [1];
+var a2 = Lambda.array(a);
+name(a) == "Array";
+name(a2) == "Array";
+a != a2;
+a2.length == 1;
+a2[0] == 1;
+var e = [];
+var e2 = Lambda.array(e);
+e != e2;
+e2.length == 0;
+
+// list
+var a = [1];
+var l = Lambda.list(a);
+name(a) == "Array";
+name(l) == "List";
+l.length == 1;
+l.first() == 1;
+var l2 = Lambda.list(l);
+name(l2) == "List";
+l != l2;
+var e = new List();
+var e2 = Lambda.list(e);
+e != e2;
+e2.length == 0;
+
+// map
+var a = [1, 2, 3];
+var b = Lambda.map(a,function(i) return i * 2);
+b.length == 3;
+b.pop() == 2;
+b.pop() == 4;
+b.pop() == 6;
+
+// mapi
+var a = [1, 2, 3];
+var total = 0;
+function myMap(index, i) {
+	total += index;
+	return i * 2;
+}
+var b = Lambda.mapi(a, myMap);
+total == 3;
+b.length == 3;
+b.pop() == 2;
+b.pop() == 4;
+b.pop() == 6;
+
+// exists
+Lambda.exists([1, 2, 3], function(i) return i == 2) == true;
+Lambda.exists([1, 2, 3], function(i) return i == 4) == false;
+Lambda.exists([], function(x) return true) == false;
+
+// foreach
+Lambda.foreach([2, 4, 6],function(i) return i % 2 == 0) == true;
+Lambda.foreach([2, 4, 7],function(i) return i % 2 == 0) == false;
+Lambda.foreach([], function(x) return false) == true;
+
+// iter
+var check = 0;
+var sum = 0;
+Lambda.iter([1,2,3],function(i) {
+	if (check != i - 1) throw "no match";
+	check = i;
+	sum += i;
+});
+check == 3;
+sum == 6;
+Lambda.iter([],function(i) return throw "no call");
+
+// filter
+Lambda.array(Lambda.filter([1,2,3,4],function(i) return i < 3)) == [1,2];
+Lambda.array(Lambda.filter([1,2,3,4],function(i) return true)) == [1,2,3,4];
+Lambda.array(Lambda.filter([1,2,3,4],function(i) return false)) == [];
+Lambda.array(Lambda.filter([],function(i) return false)) == [];
+Lambda.array(Lambda.filter([],function(i) return true)) == [];
+Lambda.array(Lambda.filter([],null)) == [];
+
+// count
+Lambda.count([1,2,3]) == 3;
+Lambda.count([1,2,3], function(x) return false) == 0;
+Lambda.count([1,2,3], function(x) return true) == 3;
+Lambda.count([1,2,3], function(x) return x % 2 == 1) == 2;
+Lambda.count([]) == 0;
+
+// empty
+Lambda.empty([]) == true;
+Lambda.empty([null]) == false;
+
+// indexOf
+Lambda.indexOf([1,2,3],1) == 0;
+Lambda.indexOf([1,2,3],2) == 1;
+Lambda.indexOf([1,2,3],3) == 2;
+Lambda.indexOf([1,2,3,3],3) == 2;
+Lambda.indexOf([1,2,3],4) == -1;
+Lambda.indexOf([],1) == -1;
+
+// concat
+Lambda.array(Lambda.concat([1,2,3],[3,4,5])) == [1,2,3,3,4,5];
+Lambda.array(Lambda.concat([1,2,3],[])) == [1,2,3];
+Lambda.array(Lambda.concat([],[1,2,3])) == [1,2,3];
+Lambda.array(Lambda.concat([],[])) == [];