Split the List library into Elm and JS code. Do profiling for many functions (map, foldr, filter, length, zipWith, scanl, last, take, reverse) and get some nice speedups.

This commit is contained in:
evancz 2013-02-10 01:45:45 -08:00
parent 784ada68a8
commit e05e9c5aca
2 changed files with 218 additions and 480 deletions

View file

@ -9,6 +9,9 @@ head = Native.head
tail : [a] -> [a]
tail = Native.tail
last : [a] -> a
last = Native.last
map : (a -> b) -> [a] -> [b]
map = Native.map
@ -19,16 +22,16 @@ foldr : (a -> b -> b) -> b -> [a] -> b
foldr = Native.foldr
foldl1 : (a -> a -> a) -> [a] -> a
foldl1 f (x::xs) = foldl f x xs
foldl1 = Native.foldl1
foldr1 : (a -> a -> a) -> [a] -> a
foldr1 f (x::xs) = foldr f x xs
foldr1 = Native.foldr1
scanl : (a -> b -> b) -> b -> [a] -> [b]
scanl f b xs = b :: (case xs of { x::xs -> scanl f (f x b) xs; [] -> [] })
scanl = Native.scanl
scanl1 : (a -> a -> a) -> [a] -> [a]
scanl1 f lst = case lst of { x::xs -> scanl f x xs; [] -> [] }
scanl1 = Native.scanl1
filter : (a -> Bool) -> [a] -> [a]
filter = Native.filter
@ -37,22 +40,25 @@ length : [a] -> Int
length = Native.length
reverse : [a] -> [a]
reverse = foldl (::) []
reverse = Native.reverse
concat = foldr (++) []
concatMap f = concat . map f
concat : [[a]] -> [a]
concat = Native.foldr (++) []
and : [Bool] -> Bool
and = foldl (&&) True
or : [Bool] -> Bool
or = foldl (||) False
any : (a -> Bool) -> [a] -> Bool
any pred = foldl (\x acc -> acc && pred x) True
concatMap : (a -> [b]) -> [a] -> [b]
concatMap f = concat . Native.map f
all : (a -> Bool) -> [a] -> Bool
all pred = foldl (\x acc -> acc || pred x) False
all pred = Native.all
any : (a -> Bool) -> [a] -> Bool
any = Native.any
and : [Bool] -> Bool
and = Native.all id
or : [Bool] -> Bool
or = Native.any id
sum = foldl (+) 0
product = foldl (*) 1

View file

@ -1,482 +1,214 @@
Elm.List = function() {
function nativeList(elm) {
var throwError = function(f) {
throw new Error("Function '" + f + "' expecting a list!");
}
function throwError(f) {
throw new Error("Function '" + f + "' expects a non-empty list!");
}
function length(xs) {
var out = 0;
while (xs[0] === "Cons") {
out += 1;
xs = xs[2];
}
return out;
};
var reverse = foldl(function(x_72) {
return function(y_73) {
return["Cons", x_72, y_73]
}
})(["Nil"]);
var concat = foldr(function(x_74) {
return function(y_75) {
return Value.append(x_74, y_75)
}
})(["Nil"]);
var and = foldl(function(x_77) {
return function(y_78) {
return x_77 && y_78
}
})(true);
var or = foldl(function(x_79) {
return function(y_80) {
return x_79 || y_80
}
})(false);
var sum = foldl(function(x_89) {
return function(y_90) {
return x_89 + y_90
}
})(0);
var product = foldl(function(x_91) {
return function(y_92) {
return x_91 * y_92
}
})(1);
var maximum = foldl1(function(x) { return function(y) { return Math.max(x,y) } });
var minimum = foldl1(function(x) { return function(y) { return Math.min(x,y) } });
function head(v) {
if (v[0] !== "Cons") {
throw new Error("Error: 'head' only accepts lists of length greater than one.");
}
return v[1];
function toArray(xs) {
var out = [];
while (xs[0] === "Cons") {
out.push(xs[1]);
xs = xs[2];
}
function tail(v) {
if (v[0] !== "Cons") {
throw new Error("Error: 'tail' only accepts lists of length greater than one.");
}
return v[2];
return out;
}
function fromArray(arr) {
var out = ["Nil"];
for (var i = arr.length; i--; ) {
out = ["Cons", arr[i], out];
}
function last(v) {
if (v[0] !== "Cons") {
throw new Error("Error: 'last' only accepts lists of length greater than one.");
}
var out = v[1];
while (v[0] === "Cons") {
out = v[1];
v = v[2];
}
return out;
return out;
}
function head(v) { v[0] === "Nil" ? throwError('head') : return v[1]; }
function tail(v) { v[0] === "Nil" ? throwError('tail') : return v[2]; }
function last(xs) {
if (xs[0] === "Nil") { throwError('last'); }
var out = xs[1];
while (xs[0] === "Cons") {
out = xs[1];
xs = xs[2];
}
function map(f) {
return function(xs) {
if (xs[0] === "Nil") { return xs; }
if (xs[0] !== "Cons") { throwError('map'); }
var root = ["Cons", f(xs[1]), ["Nil"]];
var curr = root;
xs = xs[2];
while (xs[0]==="Cons") {
curr[2] = ["Cons", f(xs[1]), ["Nil"]];
xs = xs[2];
curr = curr[2];
}
return root;
}
return out;
}
function map(f) { return function(xs) {
var arr = [];
while (xs[0] === "Cons") {
arr.push(f(xs[1]));
xs = xs[2];
}
function foldl(f) {
return function(b) {
return function(xs) {
var acc = b;
if (xs[0] === "Nil") { return acc; }
if (xs[0] !== "Cons") { throwError('foldl'); }
while (xs[0] === "Cons") {
acc = f(xs[1])(acc);
xs = xs[2];
}
return acc;
}
}
return fromArray(arr);
}
}
function foldl(f) { return function(b) { return function(xs) {
var acc = b;
while (xs[0] === "Cons") {
acc = f(xs[1])(acc);
xs = xs[2];
}
return acc;
}
function foldr(f) {
return function(b) {
return function(xs) {
var acc = b;
if (xs[0] === "Nil") { return acc; }
if (xs[0] !== "Cons") { throwError('foldr'); }
var arr = [];
while (xs[0] === "Cons") {
arr.push(xs[1]);
xs = xs[2];
}
for (var i = arr.length; i--; ) {
acc = f(arr[i])(acc);
}
return acc;
}
}
}
}
function foldr(f) { return function(b) { return function(xs) {
var arr = toArray(xs);
var acc = b;
for (var i = arr.length; i--; ) {
acc = f(arr[i])(acc);
}
return acc;
}
function foldl1(f_49) {
return function(_temp_50) {
return function(v) {
if("Cons" !== v[0]) {
return undefined
}else {
var x_51 = v[1];
var xs_52 = v[2];
return foldl(f_49)(x_51)(xs_52)
}
}(_temp_50)
}
}
}
function foldl1(f) { return function(xs) {
xs[0] === "Nil" ? throwError('foldl1') : return foldl(f)(xs[1])(xs[2]);
}
}
function foldr1(f) { return function(xs) {
if (xs[0] === "Nil") { throwError('foldr1'); }
var arr = toArray(xs);
var acc = arr.pop();
for (var i = arr.length; i--; ) {
acc = f(arr[i])(acc);
}
function foldr1(f) {
return function(xs) {
if (xs[0] === "Nil") { throw new Error("'foldr1' requires an non-empty list.") }
if (xs[0] !== "Cons") { throwError('foldr1'); }
var arr = [];
while (xs[0] === "Cons") {
arr.push(xs[1]);
xs = xs[2];
}
var acc = arr.pop();
for (var i = arr.length; i--; ) {
acc = f(arr[i])(acc);
}
return acc;
}
return acc;
}
}
function scanl(f) { return function(b) { return function(xs) {
var arr = toArray(xs);
arr.unshift(b);
var len = arr.length;
for (var i = 1; i < len; ++i) {
arr[i] = f(arr[i])(arr[i-1]);
}
return fromArray(arr);
}
function scanl(f) {
return function(b) {
return function(xs) {
if (xs[0] === "Nil") { return ["Cons",b,["Nil"]]; }
if (xs[0] !== "Cons") { throwError('scanl'); }
var arr = [b];
while (xs[0] === "Cons") {
b = f(xs[1])(b);
arr.push(b);
xs = xs[2];
}
var out = ["Nil"];
for (var i = arr.length; i--; ) {
out = ["Cons", arr[i], out];
}
return out;
}
}
}
}
function scanl1(f) { return function(xs) {
xs[0] === "Nil" ? throwError('scanl1') : return scanl(f)(xs[1])(xs[2]);
}
}
function filter(pred) { return function(xs) {
var arr = [];
while (xs[0] === "Cons") {
if (pred(xs[1])) { arr.push(xs[1]); }
xs = xs[2];
}
function scanl1(f) {
return function(xs) {
if (xs[0] !== "Cons") {
throw new Error("Error: 'scanl1' requires a list of at least length 1.");
}
return scanl(f)(xs[1])(xs[2]);
}
return fromArray(arr);
}
}
function length(xs) {
var out = 0;
while (xs[0] === "Cons") {
out += 1;
xs = xs[2];
}
function filter(pred) {
return function(xs) {
if (xs[0] === "Nil") { return xs; }
if (xs[0] !== "Cons") { throwError('filter'); }
var arr = [];
while (xs[0] === "Cons") {
if (pred(xs[1])) { arr.push(xs[1]); }
xs = xs[2];
}
var out = ["Nil"];
for (var i = arr.length; i--; ) {
out = ["Cons", arr[i], out];
}
return out;
}
return out;
}
function reverse(xs) { return fromArray(toArray(xs).reverse()); }
function all(pred) { return function(xs) {
while (xs[0] === "Cons") {
if (!pred(xs[1])) return false;
xs = xs[2];
}
function concatMap(f_76) {
return function(x) {
return concat(map(f_76)(x))
}
return true;
}
}
function any(pred) { return function(xs) {
while (xs[0] === "Cons") {
if (pred(xs[1])) return true;
xs = xs[2];
}
function all(pred) {
return foldl(function(x) { return function(acc) {
return acc && pred(x);
};})(true);
return false;
}
}
function zipWith(f) { return function(xs) { return function(ys) {
var arr = [];
while (xs[0] === "Cons" && ys[0] === "Cons") {
arr.push(f(xs[1])(ys[1]));
xs = xs[2];
ys = ys[2];
}
return fromArray(arr);
}
function any(pred) {
return foldl(function(x) { return function(acc) {
return acc || pred(x);
};})(false);
}
}
function zip(xs) { return function(ys) {
var arr = [];
while (xs[0] === "Cons" && ys[0] === "Cons") {
arr.push(["Tuple2",xs[1],ys[1]]);
xs = xs[2];
ys = ys[2];
}
function partition(pred_93) {
return function(lst_94) {
return function() {
var v = lst_94;
var c = [function(v) {
if("Nil" !== v[0]) {
return undefined
}else {
return["Tuple2", ["Nil"], ["Nil"]]
}
}, function(v) {
if("Cons" !== v[0]) {
return undefined
}else {
var x_95 = v[1];
var xs_96 = v[2];
return function(v) {
if("Tuple2" !== v[0]) {
return undefined
}else {
var as_97 = v[1];
var bs_98 = v[2];
return pred_93(x_95) ? ["Tuple2", ["Cons", x_95, as_97], bs_98] : ["Tuple2", as_97, ["Cons", x_95, bs_98]]
}
}(partition(pred_93)(xs_96))
}
}];
for(var i = c.length;i--;) {
var r = c[i](v);
if(r !== undefined) {
return r
}
}
}()
}
return fromArray(arr);
}
}
function sort(xs) {
return fromArray(toArray(xs).sort(function(a,b) { return a - b}));
}
function take(n) { return function(xs) {
var arr = [];
while (xs[0] === "Cons" && n > 0) {
arr.push(xs[1]);
xs = xs[2];
--n;
}
function zipWith(f) {
return function(listA) {
return function(listB) {
if (listA[0] === "Nil" || listB[0] === "Nil") { return ["Nil"]; }
if (listA[0] !== "Cons" || listB[0] !== "Cons") { throwError('zipWith'); }
var arr = [];
while (listA[0] === "Cons" && listB[0] === "Cons") {
arr.push(f(listA[1])(listB[1]));
listA = listA[2];
listB = listB[2];
}
var out = ["Nil"];
for (var i = arr.length; i--; ) {
out = ["Cons", arr[i], out];
}
return out;
}
}
return fromArray(arr);
}
}
function drop(n) { return function(xs) {
while (xs[0] === "Cons" && n > 0) {
xs = xs[2];
--n;
}
function zip(listA) {
return function(listB) {
if (listA[0] === "Nil" || listB[0] === "Nil") { return ["Nil"]; }
if (listA[0] !== "Cons" || listB[0] !== "Cons") { throwError('zip'); }
var arr = [];
while (listA[0] === "Cons" && listB[0] === "Cons") {
arr.push(["Tuple2", listA[1], listB[1]]);
listA = listA[2];
listB = listB[2];
}
var out = ["Nil"];
for (var i = arr.length; i--; ) {
out = ["Cons", arr[i], out];
}
return out;
}
}
function unzip(pairs_112) {
return function() {
var v = pairs_112;
var c = [function(v) {
if("Nil" !== v[0]) {
return undefined
}else {
return["Tuple2", ["Nil"], ["Nil"]]
}
}, function(v) {
if("Cons" !== v[0]) {
return undefined
}else {
var p_113 = v[1];
var ps_114 = v[2];
return function(v) {
if("Tuple2" !== v[0]) {
return undefined
}else {
if("Tuple2" !== v[1][0]) {
return undefined
}else {
var x_115 = v[1][1];
var y_116 = v[1][2];
if("Tuple2" !== v[2][0]) {
return undefined
}else {
var xs_117 = v[2][1];
var ys_118 = v[2][2];
return["Tuple2", ["Cons", x_115, xs_117], ["Cons", y_116, ys_118]]
}
}
}
}(["Tuple2", p_113, unzip(ps_114)])
}
}];
for(var i = c.length;i--;) {
var r = c[i](v);
if(r !== undefined) {
return r
}
}
}()
}
function intersperse(sep_119) {
return function(xs_120) {
return function() {
var v = xs_120;
var c = [function(v) {
if("Nil" !== v[0]) {
return undefined
}else {
return["Nil"]
}
}, function(v) {
if("Cons" !== v[0]) {
return undefined
}else {
var a_124 = v[1];
if("Nil" !== v[2][0]) {
return undefined
}else {
return["Cons", a_124, ["Nil"]]
}
}
}, function(v) {
if("Cons" !== v[0]) {
return undefined
}else {
var a_121 = v[1];
if("Cons" !== v[2][0]) {
return undefined
}else {
var b_122 = v[2][1];
var cs_123 = v[2][2];
return["Cons", a_121, ["Cons", sep_119, intersperse(sep_119)(["Cons", b_122, cs_123])]]
}
}
}];
for(var i = c.length;i--;) {
var r = c[i](v);
if(r !== undefined) {
return r
}
}
}()
}
}
function intercalate(sep_125) {
return function(xs_126) {
return function() {
var v = xs_126;
var c = [function(v) {
if("Nil" !== v[0]) {
return undefined
}else {
return["Nil"]
}
}, function(v) {
if("Cons" !== v[0]) {
return undefined
}else {
var a_130 = v[1];
if("Nil" !== v[2][0]) {
return undefined
}else {
return a_130
}
}
}, function(v) {
if("Cons" !== v[0]) {
return undefined
}else {
var a_127 = v[1];
if("Cons" !== v[2][0]) {
return undefined
}else {
var b_128 = v[2][1];
var cs_129 = v[2][2];
return Value.append(a_127, Value.append(sep_125, intercalate(sep_125)(["Cons", b_128, cs_129])))
}
}
}];
for(var i = c.length;i--;) {
var r = c[i](v);
if(r !== undefined) {
return r
}
}
}()
}
}
function sort(xs) {
if (xs[0] === "Nil") { return xs; }
if (xs[0] !== "Cons") { throwError('sort'); }
var arr = [];
while (xs[0] === "Cons") {
arr.push(xs[1]);
xs = xs[2];
}
arr.sort(function(a,b) { return a - b});
var out = ["Nil"];
for (var i = arr.length; i--; ) {
out = [ "Cons", arr[i], out ];
}
return out;
}
function take(n) { return function(xs) {
if (n <= 0) { return ["Nil"]; }
if (xs[0] === "Nil") { return xs; }
if (xs[0] !== "Cons") { throwError('take'); }
var out = [ "Cons", xs[1], ["Nil"] ];
var temp = out;
xs = xs[2];
--n;
while (xs[0] === "Cons" && n > 0) {
temp[2] = [ "Cons", xs[1], ["Nil"] ];
temp = temp[2];
xs = xs[2];
--n;
}
return out;
};
}
function drop(n) { return function(xs) {
if (xs[0] === "Nil") { return xs; }
if (xs[0] !== "Cons") { throwError('drop'); }
while (xs[0] === "Cons" && n > 0) {
xs = xs[2];
--n;
}
return xs;
};
}
return {head:head,
tail:tail,
last:last,
map:map,
foldl:foldl,
foldr:foldr,
foldl1:foldl1,
foldr1:foldr1,
scanl:scanl,
scanl1:scanl1,
filter:filter,
length:length,
reverse:reverse,
concat:concat,
concatMap:concatMap,
and:and,
or:or,
all:all,
any:any,
sum:sum,
product:product,
maximum:maximum,
minimum:minimum,
partition:partition,
zipWith:zipWith,
zip:zip,
unzip:unzip,
intersperse:intersperse,
intercalate:intercalate,
sort:sort,
take:take,
drop:drop};
}();
return xs;
}
}
function concatA(
elm.Native.List = {
head:head,
tail:tail,
last:last,
map:map,
foldl:foldl,
foldr:foldr,
foldl1:foldl1,
foldr1:foldr1,
scanl:scanl,
scanl1:scanl1,
filter:filter,
length:length,
reverse:reverse,
all:all,
any:any,
zipWith:zipWith,
zip:zip,
sort:sort,
take:take,
drop:drop};
}