Created
September 14, 2013 14:05
-
-
Save jj-jabb/6562312 to your computer and use it in GitHub Desktop.
JavaScript immutable List and Lens implementation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var List = (function() { | |
function List(src) { | |
this._list = null | |
this._length = 0 | |
if(src instanceof List) { | |
this._list = src._list | |
this._length = src._length | |
} | |
} | |
List.fromArray = function(src) { | |
var list = new List() | |
for (var i = src.length - 1; i >= 0; i--) { | |
list = list.push(src[i]) | |
} | |
return list; | |
} | |
List.prototype = { | |
head: function () { | |
return this._list === null ? null : this._list.head; | |
}, | |
tail: function () { | |
return this._list === null ? null : this._list.tail; | |
}, | |
push: function (value) { | |
var result = new List(this) | |
result._list = { head: value, tail: this._list === null ? null : this } | |
result._length = result._length + 1 | |
return result | |
}, | |
length: function () { | |
return this._length | |
}, | |
map: function (fn) { | |
var arr = [] | |
var list = this | |
while(list !== null) { | |
arr.push(fn(list.head())) | |
list = list.tail() | |
} | |
return List.fromArray(arr) | |
} | |
} | |
return List | |
})(); | |
var Lens = (function() { | |
function copy(src) { | |
if (src === null || typeof src !== "object") return obj; | |
if (src instanceof Date) { | |
var date = new Date() | |
date.setTime(src.getTime()) | |
return date | |
} | |
// Lists are immutable | |
if (src instanceof List) return src | |
if (src instanceof Array) return List.fromArray(src) | |
if (src instanceof Object) { | |
var obj = {}; | |
for (var attribute in src) { | |
if (src.hasOwnProperty(attribute)) { | |
obj[attribute] = src[attribute] | |
} | |
} | |
return obj | |
} | |
} | |
function Lens(fieldName) { | |
this._fieldName = fieldName; | |
} | |
Lens.copyObject = copy | |
Lens.prototype = { | |
get: function(model) { | |
if (!model) { | |
return this.get | |
} | |
return model[this._fieldName] | |
}, | |
set: function(value, model) { | |
var self = this; | |
if (!model) { | |
return function(m) { | |
return self.set(value, m) | |
} | |
} | |
var result = copy(model) | |
result[this._fieldName] = value | |
return result | |
}, | |
modify: function(fn, model) { | |
var self = this; | |
if (!model) { | |
return function(m) { | |
return self.modify(fn, m) | |
} | |
} | |
return this.set(fn(this.get(model)), model) | |
}, | |
compose: function(lens) { | |
return new ComposedLens(this, lens) | |
} | |
} | |
function ComposedLens(lens1, lens2) { | |
this._lens1 = lens1; | |
this._lens2 = lens2; | |
} | |
ComposedLens.prototype = { | |
get: function(model) { | |
if (!model) { | |
return this.get | |
} | |
return this._lens2.get(this._lens1.get(model)) | |
}, | |
set: function(value, model) { | |
var self = this | |
if (!model) { | |
return function(m) { | |
return self.set(value, m) | |
} | |
} | |
return this._lens1.modify(this._lens2.set(value), model) | |
}, | |
modify: Lens.prototype.modify, | |
compose: Lens.prototype.compose | |
} | |
return Lens | |
})(); | |
// some simple tests | |
var sqr = function(x) { return x * x } | |
var l0 = List.fromArray([10, 11]) | |
var l1 = l0.map(sqr) | |
// need to figure out how to push into a list (i.e. author could have a list of cars) | |
var car = { | |
color: "red" | |
} | |
var author = { | |
name: "bob", | |
car: car | |
} | |
var book = { | |
title: "blarg", | |
author: author | |
} | |
var bookTitle = new Lens("title") | |
var bookAuthor = new Lens("author") | |
var authorName = new Lens("name") | |
var authorCar = new Lens("car") | |
var carColor = new Lens("color") | |
var bookAuthorName = bookAuthor.compose(authorName) | |
var bookAuthorCarColor = bookAuthor.compose(authorCar).compose(carColor); | |
var title = bookTitle.get(book) | |
var bookb = bookTitle.set("zombies", book) | |
var bookc = bookAuthorName.set("joe", book) | |
var bookd = bookAuthorCarColor.set("blue", book) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment