Here is a pack of useful functions that let you operate on arrays and integers
PHP Code:
//#CLIENTSIDE
function onCreated() {
/* MISCELLANEOUS FUNCTIONS */
// Return whatever is passed in
this.id = function (temp.a) {
return temp.a;
};
// Return the first parameter and ignore the second.
this.const = function (temp.a, temp.b) {
return temp.a;
};
// Combine two functions and return a new function which executes them in order.
// i.e., compose(f, g)(x) = f(g(x))
this.compose = function (temp.f1, temp.f2) {
temp.f = function (temp.x) {
temp.f1 = this.(@"freevars_"@temp).f1;
temp.f2 = this.(@"freevars_"@temp).f2;
return (@temp.f1)((@temp.f2)(temp.x));
};
this.(@"freevars_"@temp.f).f1 = temp.f1;
this.(@"freevars_"@temp.f).f2 = temp.f2;
return temp.f;
};
// Flip the parameters of a function.
// flip(f)(x, y) = f(y,x)
this.flip = function (temp.f1) {
temp.f = function (temp.a, temp.b) {
temp.f1 = this.(@"freevars_"@temp.f).f1;
return (@temp.f1)(temp.b, temp.a);
};
this.(@"freevars_"@temp.f).f1 = temp.f1;
return temp.f;
};
// Until p(x) is true, x = f(x) every recursive step. Return the final x (after all the fs are applied).
this.until = function (temp.p, temp.f, temp.x) {
if ((@temp.p)(temp.x)) {
return temp.x;
} else {
return (@temp)(temp.p, temp.f, (@temp.f)(temp.p));
}
};
/* BOOLEAN OPERATIONS */
// Just negates a boolean. Useful for composing.
this.not = function (temp.a) {
return !temp.a;
};
/* NUMERIC OPERATIONS */
// Negates a number.
this.negate = function (temp.a) {
return -temp.a;
};
// Get the sign of a number.
this.signum = function (temp.a) {
if (temp.a < 0) {
return -1;
} else if (temp.a == 0) {
return 0;
} else {
return 1;
}
};
// Return the remainder of an integer division.
this.rem = function(temp.a, temp.n) {
return temp.a - temp.n*int(temp.a/temp.n);
};
// Subtract two numbers.
this.subtract = function (temp.a, temp.b) {
return temp.b - temp.a;
};
// Checks if a number is even
this.even = function (temp.a) {
temp.a = temp.a/2;
return int(temp.a) != temp.a;
};
// Checks if a number is odd
this.odd = this.compose(this.not, this.even);
// Returns the greatest positive integer that divides both x and y.
this.gcd = function (temp.x, temp.y) {
temp.gcd2 = function (temp.a, temp.b) {
if (temp.b == 0) {
return temp.a;
} else {
return (@temp)(temp.b, this.rem(temp.a, temp.b));
}
};
if (temp.x == 0 && temp.y == 0) {
// error
} else {
return (@temp.gcd2)(abs(temp.x), abs(temp.y));
}
};
// Returns the smallest integer that both x and y divide.
this.lcm = function (temp.x, temp.y) {
if (temp.x == 0 || temp.y == 0) {
return 0;
} else {
return abs((temp.x / (this.gcd(temp.x, temp.y))) * temp.y);
}
};
/* LIST OPERATIONS */
// Take a function and a list. Return a new list that has that function applied across it.
this.map = function (temp.f, temp.a) {
temp.s = temp.a.size();
temp.b = {};
for (temp.i = 0; temp.i < temp.s; temp.i++) {
temp.b.insert(temp.i, (@temp.f)(temp.a[temp.i]));
}
return temp.b;
};
// Take a function and a list. Return a list that only has elements where temp.f was True for them.
this.filter = function (temp.f, temp.a) {
temp.s = temp.a.size();
temp.b = {};
for (temp.i = 0; temp.i < temp.s; temp.i++) {
if ((@temp.f)(temp.a[temp.i]) == true) {
temp.b.add(temp.a[temp.i]);
}
}
return temp.b;
};
// return the first element in a list.
this.head = function (temp.a) {
return temp.a[0];
};
// return the last element of the list.
this.last = function (temp.a) {
return temp.a[temp.a.size()-1];
};
// return everything but the first element in a list.
this.tail = function (temp.a) {
return temp.a.subarray(1);
};
// return everything but the last element in a list.
this.init = function (temp.a) {
return temp.a.subarray(0, temp.a.size()-2);
};
// takes a list and returns a new list that in reverse.
this.reverse = function (temp.a) {
temp.aSize = temp.a.size();
temp.b = new [temp.aSize];
for (temp.i = 0; temp.i < temp.aSize; temp.i++) {
temp.b[temp.i] = temp.a[temp.aSize-1-temp.i];
}
return temp.b;
};
// Takes a 2-parameter function, a value, and a list of values, and combines the array into a new value based on that function moving from the left to the right.
this.foldl = function (temp.f, temp.init, temp.a) {
temp.s = temp.a.size();
temp.result = temp.init;
for (temp.i = 0; temp.i < temp.s; temp.i++) {
temp.result = (@temp.f)(temp.result, temp.a[temp.i]);
}
return temp.result;
};
// Same as foldl, but no default value (the list must not be empty in this case).
this.foldl1 = function (temp.f, temp.a) {
temp.s = temp.a.size();
temp.result = temp.a[0];
for (temp.i = 1; temp.i < temp.s; temp.i++) {
temp.result = (@temp.f)(temp.result, temp.a[temp.i]);
}
return temp.result;
};
// Same as foldl but starts from the right of the list and moves left.
this.foldr = function (temp.f, temp.init, temp.a) {
temp.s = temp.a.size();
temp.result = temp.init;
for (temp.i = temp.s-1; temp.i >= 0; temp.i--) {
temp.result = (@temp.f)(temp.a[temp.i], temp.result);
}
return temp.result;
};
// same as foldr but with no default value (list must be non-empty).
this.foldr1 = function (temp.f, temp.a) {
temp.s = temp.a.size();
temp.result = temp.a[temp.s-1];
for (temp.i = temp.s-2; temp.i >= 0; temp.i--) {
temp.result = (@temp.f)(temp.a[temp.i], temp.result);
}
return temp.result;
};
/* sublists */
// takes the first temp.num values from a list
this.takee = function (temp.num, temp.a) {
return temp.a.subarray(0, temp.num);
};
// drops the first temp.num values from a list
this.drop = function (temp.num, temp.a) {
return temp.a.subarray(temp.num);
};
// splits a list into two parts at temp.num
this.splitAt = function (temp.num, temp.a) {
return {temp.a.subarray(0, temp.num), temp.a.subarray(temp.num)};
};
// keep taking elements from temp.xs until temp.p is false on that element.
this.takeWhile = function (temp.p, temp.xs) {
temp.xsSize = temp.xs.size();
temp.n = {};
for (temp.i = 0; temp.i < temp.xsSize; temp.i++) {
if ((@temp.p)(temp.xs[temp.i])) {
temp.n.add(temp.xs[temp.i]);
} else {
break;
}
}
return temp.n;
};
// keep dropping elements from temp.xs while temp.p is true on that element.
this.dropWhile = function (temp.p, temp.xs) {
temp.xsSize = temp.xs.size();
temp.n = {};
for (temp.i = 0; temp.i < temp.xsSize; temp.i++) {
if (!(@temp.p)(temp.xs[temp.i])) {
break;
}
}
for (temp.x = temp.i; temp.x < temp.xsSize; temp.x++) {
temp.n.add(temp.xs[temp.x]);
}
return temp.n;
};
// splits an array into two based on the function temp.p. This is basically {takeWhile(p,xs), dropWhile(p,xs)}
this.span = function (temp.p, temp.xs) {
temp.xsSize = temp.xs.size();
temp.n = {};
for (temp.i = 0; temp.i < temp.xsSize; temp.i++) {
if ((@temp.p)(temp.xs[temp.i])) {
temp.n.add(temp.xs[temp.i]);
} else {
break;
}
}
temp.n2 = {};
for (temp.x = temp.i; temp.x < temp.xsSize; temp.x++) {
temp.n2.add(temp.xs[temp.x]);
}
return {temp.n, temp.n2};
};
// span, but with a negated temp.p
this.break = function (temp.p, temp.xs) {
return this.span(this.compose(this.not, temp.p), temp.xs);
};
}
Put this in a class, e.g.,
prelude, then:
PHP Code:
temp.p = new TStaticVar();
temp.p.join("prelude");
temp.f = function (temp.x) { return temp.x*2; }
echo(temp.p.map(temp.f, {1,2,3,4})); // returns {2,4,6,8}
Inspired by the
Haskell Prelude. Also note there is some more documentation/examples at that link for the functions I provided. (Also more functions that I haven't converted to GS yet.)