Created
March 28, 2015 13:36
-
-
Save eddmann/6d18aa8a50eb5f64e9ed to your computer and use it in GitHub Desktop.
JS Bin // source http://jsbin.com/vosiye
This file contains 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
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="utf-8"> | |
<title>JS Bin</title> | |
</head> | |
<body> | |
<script id="jsbin-javascript"> | |
"use strict"; | |
var _toArray = function (arr) { return Array.isArray(arr) ? arr : Array.from(arr); }; | |
var _inherits = function (subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) subClass.__proto__ = superClass; }; | |
var _prototypeProperties = function (child, staticProps, instanceProps) { if (staticProps) Object.defineProperties(child, staticProps); if (instanceProps) Object.defineProperties(child.prototype, instanceProps); }; | |
console.clear(); | |
var log = function (x) { | |
return console.log(x ? x.toString() : x); | |
}; | |
var curry = function (fn) { | |
for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { | |
args[_key - 1] = arguments[_key]; | |
} | |
var _curry = function (args) { | |
return args.length < fn.length ? function () { | |
for (var _len2 = arguments.length, _args = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { | |
_args[_key2] = arguments[_key2]; | |
} | |
return _curry([].concat(_toArray(args), _toArray(_args))); | |
} : fn.apply(undefined, _toArray(args)); | |
}; | |
return _curry(args); | |
}; | |
var compose = function () { | |
for (var _len = arguments.length, fns = Array(_len), _key = 0; _key < _len; _key++) { | |
fns[_key] = arguments[_key]; | |
} | |
return fns.reduce(function (f, g) { | |
return function () { | |
for (var _len2 = arguments.length, args = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { | |
args[_key2] = arguments[_key2]; | |
} | |
return f(g.apply(undefined, _toArray(args))); | |
}; | |
}); | |
}; | |
var fmap = curry(function (fn, functor) { | |
return functor.fmap(fn); | |
}), | |
bind = curry(function (fn, monad) { | |
return monad.bind(fn); | |
}), | |
mjoin = function (monad) { | |
return monad.bind(function (x) { | |
return x; | |
}); | |
}; | |
var Maybe = (function () { | |
var Some = function (x) { | |
this.x = x; | |
}; | |
Some.prototype.fmap = function (fn) { | |
return Maybe.of(fn(this.x)); | |
}; | |
Some.prototype.bind = function (fn) { | |
return fn(this.x); | |
}; | |
Some.prototype.toString = function () { | |
return "Some(" + this.x + ")"; | |
}; | |
var None = function () {}; | |
None.prototype.fmap = function (fn) { | |
return new None(); | |
}; | |
None.prototype.bind = function (fn) { | |
return new None(); | |
}; | |
None.prototype.toString = function () { | |
return "None"; | |
}; | |
var isNull = function (x) { | |
return x === null || x === undefined; | |
}; | |
return { | |
of: function (x) { | |
return isNull(x) ? new None() : new Some(x); | |
}, | |
lift: function (fn) { | |
return function () { | |
for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { | |
args[_key] = arguments[_key]; | |
} | |
return Maybe.of(fn.apply(undefined, _toArray(args))); | |
}; | |
}, | |
Some: Some, | |
None: None | |
}; | |
})(); | |
var isNum = function (x) { | |
return !isNaN(parseFloat(x)) && isFinite(x); | |
}, | |
add = function (a, b) { | |
return isNum(a) && isNum(b) ? a + b : null; | |
}, | |
madd = Maybe.lift(add); | |
log(add(1, 2)); // 3 | |
log(add(1, null)); // null | |
log(madd(1, 2)); // Some(3) | |
log(madd(1, null)); // None | |
var get = curry(function (prop, obj) { | |
return obj[prop]; | |
}), | |
mget = function (prop) { | |
return Maybe.lift(get(prop)); | |
}; | |
var joe = { | |
name: "Joe Bloggs", | |
age: 25, | |
address: { | |
street: "Cinder Drive" | |
} | |
}; | |
var sally = { | |
name: "Sally Ann" }; | |
log(get("age")(sally)); // undefined | |
log(mget("age")(sally)); // None | |
log(mget("age")(joe)); // Some(25) | |
var getAddressFmap = compose(fmap(mget("street")), mget("address")), | |
getAddressJoin = compose(mjoin, getAddressFmap), | |
getAddressBind = compose(mjoin, fmap(mget("street")), mget("address")); | |
log(getAddressFmap(joe)); // Some(Some(Cinder Drive)) | |
log(getAddressJoin(joe)); // Some(Cinder Drive) | |
log(getAddressBind(joe)); // Some(Cinder Drive) | |
var Maybe = (function () { | |
function Maybe() {} | |
_prototypeProperties(Maybe, { | |
of: { | |
value: function of(x) { | |
var isNull = x === undefined || x === null; | |
return isNull ? new None() : new Some(x); | |
}, | |
writable: true, | |
enumerable: true, | |
configurable: true | |
}, | |
lift: { | |
value: function lift(fn) { | |
return function () { | |
for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { | |
args[_key] = arguments[_key]; | |
} | |
return Maybe.of(fn.apply(undefined, _toArray(args))); | |
}; | |
}, | |
writable: true, | |
enumerable: true, | |
configurable: true | |
} | |
}, { | |
of: { | |
value: function of(x) { | |
return Maybe.of(x); | |
}, | |
writable: true, | |
enumerable: true, | |
configurable: true | |
} | |
}); | |
return Maybe; | |
})(); | |
var None = (function (Maybe) { | |
function None() { | |
if (Object.getPrototypeOf(None) !== null) { | |
Object.getPrototypeOf(None).apply(this, arguments); | |
} | |
} | |
_inherits(None, Maybe); | |
_prototypeProperties(None, null, { | |
fmap: { | |
value: function fmap(fn) { | |
return this; | |
}, | |
writable: true, | |
enumerable: true, | |
configurable: true | |
}, | |
bind: { | |
value: function bind(fn) { | |
return this; | |
}, | |
writable: true, | |
enumerable: true, | |
configurable: true | |
}, | |
toString: { | |
value: function toString() { | |
return "None"; | |
}, | |
writable: true, | |
enumerable: true, | |
configurable: true | |
} | |
}); | |
return None; | |
})(Maybe); | |
var Some = (function (Maybe) { | |
function Some(x) { | |
this.x = x; | |
} | |
_inherits(Some, Maybe); | |
_prototypeProperties(Some, null, { | |
fmap: { | |
value: function fmap(fn) { | |
return this.of(fn(this.x)); | |
}, | |
writable: true, | |
enumerable: true, | |
configurable: true | |
}, | |
bind: { | |
value: function bind(fn) { | |
return fn.call(this, this.x); | |
}, | |
writable: true, | |
enumerable: true, | |
configurable: true | |
}, | |
toString: { | |
value: function toString() { | |
return "Some(" + this.x + ")"; | |
}, | |
writable: true, | |
enumerable: true, | |
configurable: true | |
} | |
}); | |
return Some; | |
})(Maybe); | |
var doM = function (exp) { | |
var tokenize = function (exp) { | |
return exp.toString().split(/[\n;]/).slice(1, -1).map(function (s) { | |
return s.trim(); | |
}).filter(Boolean); | |
}; | |
var evaluate = function (tokens) { | |
if (tokens.length === 0) return ""; | |
var token = tokens.shift(), | |
match = undefined; | |
if (match = token.match(/^return (.+)$/)) return "return this.of(" + match[1] + ");" + evaluate(tokens); | |
if (match = token.match(/^(.+) <= (.+)$/)) return "return " + match[2] + ".bind(function(" + match[1] + ") { " + evaluate(tokens) + " });"; | |
return evaluate(tokens); | |
}; | |
return compose(Function, evaluate, tokenize)(exp)(); | |
}; | |
var street = doM(function () { | |
address <= mget("address")(joe); | |
street <= mget("street")(address); | |
return street; | |
}); | |
log(street); | |
</script> | |
<script id="jsbin-source-javascript" type="text/javascript">"use strict" | |
console.clear(); | |
let log = (x) => console.log(x ? x.toString() : x); | |
let curry = (fn, ...args) => { | |
let _curry = (args) => | |
args.length < fn.length | |
? (..._args) => _curry([...args, ..._args]) | |
: fn(...args); | |
return _curry(args); | |
}; | |
let compose = (...fns) => fns.reduce((f, g) => (...args) => f(g(...args))); | |
let fmap = curry((fn, functor) => functor.fmap(fn)), | |
bind = curry((fn, monad) => monad.bind(fn)), | |
mjoin = (monad) => monad.bind((x) => x); | |
let Maybe = (function () { | |
let Some = function (x) { this.x = x; }; | |
Some.prototype.fmap = function (fn) { return Maybe.of(fn(this.x)); }; | |
Some.prototype.bind = function (fn) { return fn(this.x); }; | |
Some.prototype.toString = function () { return `Some(${this.x})`; }; | |
let None = function () {}; | |
None.prototype.fmap = (fn) => new None; | |
None.prototype.bind = (fn) => new None; | |
None.prototype.toString = () => 'None'; | |
let isNull = (x) => x === null || x === undefined; | |
return { | |
of: (x) => isNull(x) ? new None : new Some(x), | |
lift: (fn) => (...args) => Maybe.of(fn(...args)), | |
Some, | |
None | |
}; | |
})(); | |
let isNum = (x) => !isNaN(parseFloat(x)) && isFinite(x), | |
add = (a, b) => isNum(a) && isNum(b) ? a + b : null, | |
madd = Maybe.lift(add); | |
log(add(1, 2)); // 3 | |
log(add(1, null)); // null | |
log(madd(1, 2)); // Some(3) | |
log(madd(1, null)); // None | |
let get = curry((prop, obj) => obj[prop]), | |
mget = (prop) => Maybe.lift(get(prop)); | |
let joe = { | |
name: 'Joe Bloggs', | |
age: 25, | |
address: { | |
street: 'Cinder Drive' | |
} | |
}; | |
let sally = { | |
name: 'Sally Ann', | |
}; | |
log(get('age')(sally)); // undefined | |
log(mget('age')(sally)); // None | |
log(mget('age')(joe)); // Some(25) | |
let getAddressFmap = compose(fmap(mget('street')), mget('address')), | |
getAddressJoin = compose(mjoin, getAddressFmap), | |
getAddressBind = compose(mjoin, fmap(mget('street')), mget('address')); | |
log(getAddressFmap(joe)); // Some(Some(Cinder Drive)) | |
log(getAddressJoin(joe)); // Some(Cinder Drive) | |
log(getAddressBind(joe)); // Some(Cinder Drive) | |
class Maybe { | |
static of(x) { | |
let isNull = x === undefined || x === null; | |
return isNull ? new None : new Some(x); | |
} | |
of(x) { return Maybe.of(x); } | |
static lift(fn) { return (...args) => Maybe.of(fn(...args)); } | |
} | |
class None extends Maybe { | |
fmap(fn) { return this; } | |
bind(fn) { return this; } | |
toString() { return 'None'; } | |
} | |
class Some extends Maybe { | |
constructor(x) { this.x = x; } | |
fmap(fn) { return this.of(fn(this.x)); } | |
bind(fn) { return fn.call(this, this.x); } | |
toString() { return `Some(${this.x})`; } | |
} | |
let doM = function(exp) { | |
let tokenize = (exp) => { | |
return exp | |
.toString() | |
.split(/[\n;]/) | |
.slice(1, -1) | |
.map((s) => s.trim()) | |
.filter(Boolean); | |
}; | |
let evaluate = (tokens) => { | |
if (tokens.length === 0) return ''; | |
let token = tokens.shift(), match; | |
if (match = token.match(/^return (.+)$/)) | |
return `return this.of(${match[1]});` + evaluate(tokens); | |
if (match = token.match(/^(.+) <= (.+)$/)) | |
return `return ${match[2]}.bind(function(${match[1]}) { ${evaluate(tokens)} });`; | |
return evaluate(tokens); | |
}; | |
return compose(Function, evaluate, tokenize)(exp)(); | |
}; | |
let street = doM(() => { | |
address <= mget('address')(joe) | |
street <= mget('street')(address) | |
return street | |
}); | |
log(street); | |
</script></body> | |
</html> |
This file contains 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
"use strict"; | |
var _toArray = function (arr) { return Array.isArray(arr) ? arr : Array.from(arr); }; | |
var _inherits = function (subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) subClass.__proto__ = superClass; }; | |
var _prototypeProperties = function (child, staticProps, instanceProps) { if (staticProps) Object.defineProperties(child, staticProps); if (instanceProps) Object.defineProperties(child.prototype, instanceProps); }; | |
console.clear(); | |
var log = function (x) { | |
return console.log(x ? x.toString() : x); | |
}; | |
var curry = function (fn) { | |
for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { | |
args[_key - 1] = arguments[_key]; | |
} | |
var _curry = function (args) { | |
return args.length < fn.length ? function () { | |
for (var _len2 = arguments.length, _args = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { | |
_args[_key2] = arguments[_key2]; | |
} | |
return _curry([].concat(_toArray(args), _toArray(_args))); | |
} : fn.apply(undefined, _toArray(args)); | |
}; | |
return _curry(args); | |
}; | |
var compose = function () { | |
for (var _len = arguments.length, fns = Array(_len), _key = 0; _key < _len; _key++) { | |
fns[_key] = arguments[_key]; | |
} | |
return fns.reduce(function (f, g) { | |
return function () { | |
for (var _len2 = arguments.length, args = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { | |
args[_key2] = arguments[_key2]; | |
} | |
return f(g.apply(undefined, _toArray(args))); | |
}; | |
}); | |
}; | |
var fmap = curry(function (fn, functor) { | |
return functor.fmap(fn); | |
}), | |
bind = curry(function (fn, monad) { | |
return monad.bind(fn); | |
}), | |
mjoin = function (monad) { | |
return monad.bind(function (x) { | |
return x; | |
}); | |
}; | |
var Maybe = (function () { | |
var Some = function (x) { | |
this.x = x; | |
}; | |
Some.prototype.fmap = function (fn) { | |
return Maybe.of(fn(this.x)); | |
}; | |
Some.prototype.bind = function (fn) { | |
return fn(this.x); | |
}; | |
Some.prototype.toString = function () { | |
return "Some(" + this.x + ")"; | |
}; | |
var None = function () {}; | |
None.prototype.fmap = function (fn) { | |
return new None(); | |
}; | |
None.prototype.bind = function (fn) { | |
return new None(); | |
}; | |
None.prototype.toString = function () { | |
return "None"; | |
}; | |
var isNull = function (x) { | |
return x === null || x === undefined; | |
}; | |
return { | |
of: function (x) { | |
return isNull(x) ? new None() : new Some(x); | |
}, | |
lift: function (fn) { | |
return function () { | |
for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { | |
args[_key] = arguments[_key]; | |
} | |
return Maybe.of(fn.apply(undefined, _toArray(args))); | |
}; | |
}, | |
Some: Some, | |
None: None | |
}; | |
})(); | |
var isNum = function (x) { | |
return !isNaN(parseFloat(x)) && isFinite(x); | |
}, | |
add = function (a, b) { | |
return isNum(a) && isNum(b) ? a + b : null; | |
}, | |
madd = Maybe.lift(add); | |
log(add(1, 2)); // 3 | |
log(add(1, null)); // null | |
log(madd(1, 2)); // Some(3) | |
log(madd(1, null)); // None | |
var get = curry(function (prop, obj) { | |
return obj[prop]; | |
}), | |
mget = function (prop) { | |
return Maybe.lift(get(prop)); | |
}; | |
var joe = { | |
name: "Joe Bloggs", | |
age: 25, | |
address: { | |
street: "Cinder Drive" | |
} | |
}; | |
var sally = { | |
name: "Sally Ann" }; | |
log(get("age")(sally)); // undefined | |
log(mget("age")(sally)); // None | |
log(mget("age")(joe)); // Some(25) | |
var getAddressFmap = compose(fmap(mget("street")), mget("address")), | |
getAddressJoin = compose(mjoin, getAddressFmap), | |
getAddressBind = compose(mjoin, fmap(mget("street")), mget("address")); | |
log(getAddressFmap(joe)); // Some(Some(Cinder Drive)) | |
log(getAddressJoin(joe)); // Some(Cinder Drive) | |
log(getAddressBind(joe)); // Some(Cinder Drive) | |
var Maybe = (function () { | |
function Maybe() {} | |
_prototypeProperties(Maybe, { | |
of: { | |
value: function of(x) { | |
var isNull = x === undefined || x === null; | |
return isNull ? new None() : new Some(x); | |
}, | |
writable: true, | |
enumerable: true, | |
configurable: true | |
}, | |
lift: { | |
value: function lift(fn) { | |
return function () { | |
for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { | |
args[_key] = arguments[_key]; | |
} | |
return Maybe.of(fn.apply(undefined, _toArray(args))); | |
}; | |
}, | |
writable: true, | |
enumerable: true, | |
configurable: true | |
} | |
}, { | |
of: { | |
value: function of(x) { | |
return Maybe.of(x); | |
}, | |
writable: true, | |
enumerable: true, | |
configurable: true | |
} | |
}); | |
return Maybe; | |
})(); | |
var None = (function (Maybe) { | |
function None() { | |
if (Object.getPrototypeOf(None) !== null) { | |
Object.getPrototypeOf(None).apply(this, arguments); | |
} | |
} | |
_inherits(None, Maybe); | |
_prototypeProperties(None, null, { | |
fmap: { | |
value: function fmap(fn) { | |
return this; | |
}, | |
writable: true, | |
enumerable: true, | |
configurable: true | |
}, | |
bind: { | |
value: function bind(fn) { | |
return this; | |
}, | |
writable: true, | |
enumerable: true, | |
configurable: true | |
}, | |
toString: { | |
value: function toString() { | |
return "None"; | |
}, | |
writable: true, | |
enumerable: true, | |
configurable: true | |
} | |
}); | |
return None; | |
})(Maybe); | |
var Some = (function (Maybe) { | |
function Some(x) { | |
this.x = x; | |
} | |
_inherits(Some, Maybe); | |
_prototypeProperties(Some, null, { | |
fmap: { | |
value: function fmap(fn) { | |
return this.of(fn(this.x)); | |
}, | |
writable: true, | |
enumerable: true, | |
configurable: true | |
}, | |
bind: { | |
value: function bind(fn) { | |
return fn.call(this, this.x); | |
}, | |
writable: true, | |
enumerable: true, | |
configurable: true | |
}, | |
toString: { | |
value: function toString() { | |
return "Some(" + this.x + ")"; | |
}, | |
writable: true, | |
enumerable: true, | |
configurable: true | |
} | |
}); | |
return Some; | |
})(Maybe); | |
var doM = function (exp) { | |
var tokenize = function (exp) { | |
return exp.toString().split(/[\n;]/).slice(1, -1).map(function (s) { | |
return s.trim(); | |
}).filter(Boolean); | |
}; | |
var evaluate = function (tokens) { | |
if (tokens.length === 0) return ""; | |
var token = tokens.shift(), | |
match = undefined; | |
if (match = token.match(/^return (.+)$/)) return "return this.of(" + match[1] + ");" + evaluate(tokens); | |
if (match = token.match(/^(.+) <= (.+)$/)) return "return " + match[2] + ".bind(function(" + match[1] + ") { " + evaluate(tokens) + " });"; | |
return evaluate(tokens); | |
}; | |
return compose(Function, evaluate, tokenize)(exp)(); | |
}; | |
var street = doM(function () { | |
address <= mget("address")(joe); | |
street <= mget("street")(address); | |
return street; | |
}); | |
log(street); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment