// Constructors
var List = function(array) {
this.head = null
}
List.cons = function(head, tail) {
var newList = new List()
if (head) {
newList.head = head
newList.tail = new List()
}
if (tail && head) { newList.tail = tail }
return newList
}
// Takes either a series of arguments or an array and builds a list
List.of = function() {
var args = Array.prototype.slice.call(arguments)
var array = Array.isArray(args[0]) ? args[0] : args
if (!array || array.length < 1 || array[0] === null) {
return List.cons()
}
return List.cons(array[0], List.of(...array.slice(1, array.length)))
}
// Methods
List.prototype.prepend = function(x) {
return List.cons(x, this)
}
List.prototype.append = function(x) {
if (this.head === null) return List.cons(x)
return List.cons(this.head, this.tail.append(x))
}
List.prototype.map = function(f) {
if (this.tail) return List.cons(f(this.head), this.tail.map(f))
return List.cons(this.head ? f(this.head) : null, null)
}
List.prototype.reduce = function(f) {
if (!this.tail) return this.head
else return f(this.head, this.tail.reduce(f))
}
List.prototype.filter = function(f) {
if (this.head === null) return List.cons()
else if (f(this.head)) return List.cons(this.head, this.tail.filter(f))
return this.tail.filter(f)
}
List.prototype.isEmpty = function() { return this.head === null }
List.prototype.toArray = function() {
return this.reduce(function(a, b) { return b ? [].concat([a], b) : [].concat([a]) })
}
var list = List.of(1, 2, 3, 4);
console.log('The list: ', JSON.stringify(list, null, 2))
console.log('Map add 1: ', JSON.stringify(list.map(function(value) { return value + 1 }), null, 2))
console.log('Reduce sum all values: ', list.reduce(function(a, b) { return a + b }))
console.log('Filter return even numbers: ', JSON.stringify(list.filter(function(value) { return value % 2 === 0 }), null, 2))