-
Notifications
You must be signed in to change notification settings - Fork 2
JavaScript
JavaScript, the Little Language That Could, is no longer just for the browser, as there are general-purpose runtimes available for it. I chose to try out Rhino, a version that runs on the JVM. Notice here that my script uses the JVM's generic IO functionality to perform functions that would normally be outside of the scope of a simple DOM-scripting tool. It took me almost no time to write this Imperative version of Euler1 because the code is lifted almost verbatim from C and Java:
// Euler1 in JavaScript
importPackage(java.io);
importPackage(java.lang);
function euler1(x) {
var i, result;
result = 0;
for (i=0; i<x; i++) {
if (i%3==0 || i%5==0) {
result += i;
}
}
return result;
}
System.out.println (euler1 (1000));
JavaScript, introduced in 1995, is a Prototype language, a style of Object-Oriented Programming in which new objects are not instantiated from classes. Instead, they are cloned and modified copies of existing instances, typically of a type Object. At its heart, an object in JavaScript is nothing more than a key-value dictionary, which makes them trivial to modify at runtime. Let's rewrite the previous example using an object:
// Euler1 in JavaScript
importPackage(java.io);
importPackage(java.lang);
// new object instance
var euler1 = {};
// dynamically add new properties and behaviors to object
euler1.range = 1000;
euler1.solver = function(x){
var i, result;
result = 0;
for (i=0; i<x; i++) {
if (i%3==0 || i%5==0) {
result += i;
}
}
return result;
}
euler1.result = euler1.solver(euler1.range);
System.out.println(euler1.result);
JavaScript also lets you write in a Functional style. Functions are first-class members, and you can write your code in Map/Filter/Reduce/Lambda, etc, but it's a bit like putting lipstick on a pig. Let's try anyway. In the following example, I define Map/Filter/Reduce and then apply them to an array of ints. There is now no mutable state - only declarations and function calls. State is managed through the careful use of recursion with accumulators and tail-call optimization:
// Euler1 in JavaScript
importPackage(java.io);
importPackage(java.lang);
// Generic recursive Map, Filter, Reduce using Tail Call Optimization
// Accumulator parameter is optional and only used by recursive calls
// Map - transform each item to something else
var map = function(ls, f, acc) {
if (typeof acc === "undefined") acc = [];
if (ls.length == 0) {
return acc;
} else {
return map(ls.slice(1,ls.length), f, [].concat(f(ls[0]), acc));
}
};
// Filter - remove selected items
var filter = function(ls, f, acc) {
if (typeof acc === "undefined") acc = [];
if (ls.length == 0) {
return acc;
} else if (f(ls[0]) == true) {
return filter(ls.slice(1,ls.length), f, [].concat(ls[0], acc));
} else {
return filter(ls.slice(1,ls.length), f, acc);
}
};
// Reduce - calculate a value based on all items
var reduce = function(ls, f, acc) {
if (ls.length == 0) {
return acc;
} else {
return reduce(ls.slice(1,ls.length), f, f(ls[0], acc));
}
};
// generate a list of ints
var range = function(i, acc) {
if (typeof acc === "undefined") acc = [];
if (i == 0) {
return acc;
} else {
return range(i-1, [].concat(acc, [i]));
}
};
// Now let's define specific versions of mapping/filtering/reducing functions
var myMap = function(ints) {
return map(ints, function(val) { return val; });
};
var myFilter = function(ints) {
return filter(ints,
function(val) { if (val%3==0 || val%5==0) return true;
else return false; });
};
var myReduce = function(ints) {
return reduce(ints,
function(x, acc) { if (typeof acc === "undefined") return x;
else return acc+x; });
};
// Now apply everything
System.out.println( myReduce(myFilter(myMap( range(999) ))) );
To execute your script, simply pass it as an argument to Rhino:
$ rhino euler1.js
233168.0
Return home