Skip to content

Instantly share code, notes, and snippets.

@SeijiEmery
Created June 3, 2017 03:36
Show Gist options
  • Save SeijiEmery/7d3d3b7d561ca669e6212c24866d9a82 to your computer and use it in GitHub Desktop.
Save SeijiEmery/7d3d3b7d561ca669e6212c24866d9a82 to your computer and use it in GitHub Desktop.
Another FRP example (JS)
//
// Observables / behaviors / whatever you want to call these are a pretty simple concept:
// instead of direct variables you operate with functions, and chains that you can mutate
// with more functions. The real work, of course, is in writing a framework / implementation
// that doesn't suck / have terrible performance, since calling 10-20 functions to read one
// variable is not exactly efficient x)
//
// A real library (eg. Rx, React) would have layers of caching and careful engineering that
// this naive implementation does not have. Nevertheless, the core idea is trivial; it's
// building an efficient implementation that's difficult.
//
(function () {
if (typeof(assert) !== "function") {
this.assert = function assert (condition, msg) {
if (!condition) {
if (msg) throw new Error("Assertion failed: "+msg);
else throw new Error("Assertion failed");
}
}
}
})();
function Observable () {}
function ObservableSource (value) {
this._value = value;
}
ObservableSource.prototype = Object.create(Observable);
ObservableSource.prototype.constructor = ObservableSource;
ObservableSource.prototype.set = function (value) { this._value = value; }
ObservableSource.prototype.value = function () { return this._value; }
function SingleObserver (parent, fcn) {
this.parent = parent;
this.fcn = fcn;
}
SingleObserver.prototype = Object.create(Observable);
SingleObserver.prototype.constructor = SingleObserver;
SingleObserver.prototype.value = function () {
return this.fcn.call(this, this.parent.value());
}
function MultiObserver (parents, fcn) {
this.fcn = fcn;
this.parents = parents;
}
MultiObserver.prototype = Object.create(Observable);
MultiObserver.prototype.constructor = MultiObserver;
MultiObserver.prototype.value = function () {
return this.fcn.apply(this, this.parents.map(function (parent) { return parent.value(); }));
}
function observe (sources, fcn) {
if (sources instanceof Array && sources.length != 1) {
return new MultiObserver(sources, fcn);
}
return new SingleObserver(sources, fcn);
}
function isObservable (x) { return typeof(x) === "object" && typeof(x.value) === "function"; }
assert(isObservable(new ObservableSource()));
assert(isObservable(new MultiObserver()));
assert(isObservable(new SingleObserver()));
assert(isObservable({ value: function (){} }));
assert(!isObservable({ value: {} }));
assert(!isObservable({}));
assert(!isObservable("fubar"));
assert(!isObservable(10));
assert(!isObservable(function () {}));
function observableBinaryFcn (a, b, fcn) {
if (isObservable(a) && isObservable(b)) {
return new MultiObserver([ a, b ], fcn);
} else if (isObservable(a)) {
return new SingleObserver(a, function (value) { return fcn(value, b); });
} else if (isObservable(b)) {
return new SingleObserver(b, function (value) { return fcn(a, value); });
} else {
return fcn(a, b);
}
}
function plus (a, b) { return observableBinaryFcn(a, b, function (a, b) { return a + b; }); }
function minus (a, b) { return observableBinaryFcn(a, b, function (a, b) { return a - b; }); }
function mul (a, b) { return observableBinaryFcn(a, b, function (a, b) { return a * b; }); }
function div (a, b) { return observableBinaryFcn(a, b, function (a, b) { return a / b; }); }
function mod (a, b) { return observableBinaryFcn(a, b, function (a, b) { return a % b; }); }
assert(plus (2, -3) == -1);
assert(minus(2, -3) == 5);
assert(mul(2, -3) == -6);
assert(div(2, -3) == -(2 / 3));
assert(mod(2, -3) == (2 % (-3)));
var Window = {
x: new ObservableSource(0.0),
y: new ObservableSource(0.0),
};
var a = new SingleObserver(Window.x, function (value) { return value + 100.0; });
var b = observe(Window.x, function (value) { return value + 100.0; });
var c = plus(Window.x, 100.0);
assert(Window.x.value() == 0);
assert(a.value() == 100.0);
assert(b.value() == 100.0);
assert(c.value() == 100.0);
Window.x.set(50.0);
assert(Window.x.value() == 50.0);
assert(a.value() == 150.0);
assert(b.value() == 150.0);
assert(c.value() == 150.0);
// console.log("Window.x = "+Window.x.value());
// console.log("1st: "+new SingleObserver(Window.x, function (value) { return value + 100; }).value());
// console.log("2nd: "+observe(Window.x, function (value) { return value + 100; }).value());
// console.log("3rd: "+plus(Window.x, 100).value());
Window.x.set(800);
Window.y.set(600);
var xt = plus(mod(plus(Window.x, 100), 200), -40);
var windowPerimeter = mul(plus(Window.x, Window.y), 2);
var windowArea = mul(Window.x, Window.y);
var windowAspect = div(Window.x, Window.y);
function writeValues () {
console.log(
"x = "+Window.x.value()+
", y = "+Window.y.value()+
", xt = "+xt.value()+
", p = "+windowPerimeter.value()+
", a = "+windowArea.value()+
", r = "+windowAspect.value()
);
}
writeValues();
for (var i = 100; i --> 0; ) {
Window.x.set(Window.x.value() + (Math.random() * 50) - 25);
writeValues();
}
x = 800, y = 600, xt = 60, p = 2800, a = 480000, r = 1.3333333333333333
x = 811.1414096900262, y = 600, xt = 71.1414096900262, p = 2822.2828193800524, a = 486684.8458140157, r = 1.351902349483377
x = 816.2675946834497, y = 600, xt = 76.26759468344972, p = 2832.5351893668994, a = 489760.55681006983, r = 1.360445991139083
x = 812.6638973946683, y = 600, xt = 72.66389739466831, p = 2825.3277947893366, a = 487598.338436801, r = 1.354439828991114
x = 813.5603960137814, y = 600, xt = 73.56039601378143, p = 2827.120792027563, a = 488136.23760826886, r = 1.3559339933563024
x = 807.5097443303093, y = 600, xt = 67.50974433030933, p = 2815.0194886606187, a = 484505.8465981856, r = 1.345849573883849
x = 792.3978895996697, y = 600, xt = 52.397889599669725, p = 2784.7957791993394, a = 475438.73375980183, r = 1.320663149332783
x = 797.7577502606437, y = 600, xt = 57.75775026064366, p = 2795.5155005212873, a = 478654.6501563862, r = 1.329596250434406
x = 809.9614890990779, y = 600, xt = 69.96148909907788, p = 2819.9229781981558, a = 485976.8934594467, r = 1.3499358151651297
x = 817.3078604741022, y = 600, xt = 77.3078604741022, p = 2834.6157209482044, a = 490384.7162844613, r = 1.362179767456837
x = 807.1250254521146, y = 600, xt = 67.12502545211464, p = 2814.2500509042293, a = 484275.0152712688, r = 1.3452083757535245
x = 792.3842651420273, y = 600, xt = 52.38426514202729, p = 2784.7685302840546, a = 475430.5590852164, r = 1.3206404419033788
x = 781.9253513356671, y = 600, xt = 41.925351335667074, p = 2763.850702671334, a = 469155.21080140024, r = 1.3032089188927785
x = 781.5086592687294, y = 600, xt = 41.50865926872939, p = 2763.017318537459, a = 468905.19556123763, r = 1.302514432114549
x = 786.087188066449, y = 600, xt = 46.087188066449016, p = 2772.174376132898, a = 471652.3128398694, r = 1.3101453134440817
x = 766.3957631331868, y = 600, xt = 26.395763133186847, p = 2732.7915262663737, a = 459837.4578799121, r = 1.2773262718886447
x = 762.3783522401936, y = 600, xt = 22.378352240193635, p = 2724.7567044803873, a = 457427.0113441162, r = 1.2706305870669894
x = 750.8052830235101, y = 600, xt = 10.805283023510128, p = 2701.6105660470203, a = 450483.1698141061, r = 1.251342138372517
x = 756.1171146691777, y = 600, xt = 16.11711466917768, p = 2712.2342293383554, a = 453670.2688015066, r = 1.2601951911152962
x = 752.6789672207087, y = 600, xt = 12.678967220708728, p = 2705.3579344414175, a = 451607.38033242524, r = 1.2544649453678478
x = 738.6347890365869, y = 600, xt = -1.3652109634131193, p = 2677.2695780731738, a = 443180.8734219521, r = 1.2310579817276448
x = 752.8310795780271, y = 600, xt = 12.83107957802713, p = 2705.6621591560543, a = 451698.6477468163, r = 1.2547184659633785
x = 734.9847904173657, y = 600, xt = -5.01520958263427, p = 2669.9695808347315, a = 440990.87425041944, r = 1.2249746506956096
x = 745.1338502112776, y = 600, xt = 5.133850211277604, p = 2690.267700422555, a = 447080.31012676656, r = 1.2418897503521293
x = 751.7314510070719, y = 600, xt = 11.731451007071882, p = 2703.4629020141438, a = 451038.87060424313, r = 1.252885751678453
x = 732.7893087523989, y = 600, xt = -7.210691247601062, p = 2665.578617504798, a = 439673.58525143936, r = 1.2213155145873316
x = 737.5216501415707, y = 600, xt = -2.478349858429283, p = 2675.0433002831414, a = 442512.99008494243, r = 1.2292027502359513
x = 727.6498130522668, y = 600, xt = -12.350186947733164, p = 2655.2996261045337, a = 436589.8878313601, r = 1.2127496884204447
x = 710.7992438017391, y = 600, xt = -29.200756198260933, p = 2621.598487603478, a = 426479.54628104344, r = 1.1846654063362319
x = 715.6434723641723, y = 600, xt = -24.35652763582766, p = 2631.2869447283447, a = 429386.0834185034, r = 1.192739120606954
x = 728.449239989277, y = 600, xt = -11.550760010723025, p = 2656.898479978554, a = 437069.5439935662, r = 1.214082066648795
x = 738.9790490851738, y = 600, xt = -1.0209509148262441, p = 2677.9580981703475, a = 443387.42945110425, r = 1.2316317484752897
x = 718.1529819616117, y = 600, xt = -21.84701803838834, p = 2636.3059639232233, a = 430891.789176967, r = 1.196921636602686
x = 697.1453469479457, y = 600, xt = 157.14534694794565, p = 2594.2906938958913, a = 418287.2081687674, r = 1.1619089115799095
x = 693.631188897416, y = 600, xt = 153.631188897416, p = 2587.262377794832, a = 416178.7133384496, r = 1.1560519814956933
x = 696.7661124886945, y = 600, xt = 156.7661124886945, p = 2593.532224977389, a = 418059.6674932167, r = 1.1612768541478242
x = 700.2520864130929, y = 600, xt = -39.74791358690709, p = 2600.504172826186, a = 420151.25184785575, r = 1.1670868106884882
x = 683.2349179196171, y = 600, xt = 143.23491791961715, p = 2566.4698358392343, a = 409940.9507517703, r = 1.1387248631993618
x = 692.990521597676, y = 600, xt = 152.99052159767598, p = 2585.981043195352, a = 415794.3129586056, r = 1.1549842026627932
x = 701.8245151033625, y = 600, xt = -38.1754848966375, p = 2603.649030206725, a = 421094.7090620175, r = 1.1697075251722708
x = 701.0193427326158, y = 600, xt = -38.98065726738423, p = 2602.0386854652315, a = 420611.60563956946, r = 1.1683655712210264
x = 709.204861021135, y = 600, xt = -30.795138978864998, p = 2618.40972204227, a = 425522.916612681, r = 1.1820081017018917
x = 713.0656526540406, y = 600, xt = -26.934347345959395, p = 2626.131305308081, a = 427839.39159242436, r = 1.188442754423401
x = 701.534994202666, y = 600, xt = -38.465005797334015, p = 2603.069988405332, a = 420920.9965215996, r = 1.1692249903377767
x = 679.33937641792, y = 600, xt = 139.33937641792, p = 2558.67875283584, a = 407603.625850752, r = 1.1322322940298666
x = 660.6042247381993, y = 600, xt = 120.60422473819926, p = 2521.2084494763985, a = 396362.53484291956, r = 1.101007041230332
x = 685.236297280062, y = 600, xt = 145.236297280062, p = 2570.472594560124, a = 411141.7783680372, r = 1.14206049546677
x = 667.9088157601655, y = 600, xt = 127.90881576016545, p = 2535.817631520331, a = 400745.2894560993, r = 1.1131813596002758
x = 684.87187421415, y = 600, xt = 144.87187421415, p = 2569.7437484283, a = 410923.12452849, r = 1.14145312369025
x = 694.6466680848971, y = 600, xt = 154.6466680848971, p = 2589.293336169794, a = 416788.00085093826, r = 1.157744446808162
x = 670.4792897682637, y = 600, xt = 130.4792897682637, p = 2540.9585795365274, a = 402287.5738609582, r = 1.1174654829471062
x = 662.6230686088093, y = 600, xt = 122.62306860880926, p = 2525.2461372176185, a = 397573.84116528556, r = 1.104371781014682
x = 680.6409137905575, y = 600, xt = 140.64091379055753, p = 2561.281827581115, a = 408384.5482743345, r = 1.1344015229842626
x = 667.2909192973748, y = 600, xt = 127.29091929737478, p = 2534.5818385947496, a = 400374.5515784249, r = 1.1121515321622912
x = 691.4108746103011, y = 600, xt = 151.4108746103011, p = 2582.821749220602, a = 414846.52476618066, r = 1.1523514576838352
x = 695.4242332256399, y = 600, xt = 155.4242332256399, p = 2590.84846645128, a = 417254.53993538395, r = 1.1590403887093998
x = 689.4368170876987, y = 600, xt = 149.43681708769873, p = 2578.8736341753975, a = 413662.09025261924, r = 1.1490613618128311
x = 666.9139718054794, y = 600, xt = 126.91397180547938, p = 2533.8279436109588, a = 400148.3830832876, r = 1.1115232863424656
x = 648.4661930473521, y = 600, xt = 108.46619304735214, p = 2496.9323860947043, a = 389079.7158284113, r = 1.0807769884122536
x = 658.9438696275465, y = 600, xt = 118.94386962754652, p = 2517.887739255093, a = 395366.3217765279, r = 1.0982397827125776
x = 644.1252282238565, y = 600, xt = 104.12522822385654, p = 2488.250456447713, a = 386475.1369343139, r = 1.073542047039761
x = 636.2589447991922, y = 600, xt = 96.25894479919225, p = 2472.5178895983845, a = 381755.36687951535, r = 1.0604315746653203
x = 628.0233757453971, y = 600, xt = 88.02337574539706, p = 2456.046751490794, a = 376814.02544723824, r = 1.0467056262423284
x = 613.8944733073004, y = 600, xt = 73.89447330730036, p = 2427.7889466146007, a = 368336.6839843802, r = 1.0231574555121672
x = 636.1213543452322, y = 600, xt = 96.12135434523225, p = 2472.2427086904645, a = 381672.81260713935, r = 1.0602022572420537
x = 611.7849749745801, y = 600, xt = 71.78497497458011, p = 2423.56994994916, a = 367070.98498474807, r = 1.0196416249576334
x = 603.5669230506755, y = 600, xt = 63.56692305067554, p = 2407.133846101351, a = 362140.1538304053, r = 1.005944871751126
x = 601.2897957232781, y = 600, xt = 61.289795723278075, p = 2402.579591446556, a = 360773.87743396685, r = 1.0021496595387969
x = 619.8490461101755, y = 600, xt = 79.84904611017555, p = 2439.698092220351, a = 371909.42766610533, r = 1.0330817435169592
x = 610.8947806060314, y = 600, xt = 70.89478060603142, p = 2421.789561212063, a = 366536.86836361885, r = 1.018157967676719
x = 596.0735492408276, y = 600, xt = 56.07354924082756, p = 2392.147098481655, a = 357644.12954449654, r = 0.9934559154013792
x = 591.593876236584, y = 600, xt = 51.59387623658404, p = 2383.187752473168, a = 354956.3257419504, r = 0.9859897937276401
x = 595.3466177452356, y = 600, xt = 55.34661774523556, p = 2390.693235490471, a = 357207.97064714134, r = 0.992244362908726
x = 577.0082934643142, y = 600, xt = 37.00829346431419, p = 2354.0165869286284, a = 346204.9760785885, r = 0.9616804891071903
x = 561.7939478135668, y = 600, xt = 21.793947813566774, p = 2323.5878956271335, a = 337076.36868814006, r = 0.9363232463559447
x = 570.4965196317062, y = 600, xt = 30.496519631706178, p = 2340.9930392634124, a = 342297.9117790237, r = 0.9508275327195103
x = 546.8247958109714, y = 600, xt = 6.824795810971409, p = 2293.649591621943, a = 328094.87748658285, r = 0.9113746596849523
x = 566.1859879735857, y = 600, xt = 26.185987973585725, p = 2332.3719759471714, a = 339711.59278415143, r = 0.9436433132893095
x = 572.4456686526537, y = 600, xt = 32.445668652653694, p = 2344.8913373053074, a = 343467.4011915922, r = 0.9540761144210895
x = 562.2193172457628, y = 600, xt = 22.219317245762795, p = 2324.4386344915256, a = 337331.5903474577, r = 0.9370321954096047
x = 563.0982828442939, y = 600, xt = 23.098282844293863, p = 2326.1965656885877, a = 337858.9697065763, r = 0.9384971380738231
x = 538.8428039499559, y = 600, xt = -1.1571960500441492, p = 2277.6856078999117, a = 323305.6823699735, r = 0.898071339916593
x = 532.8662855084985, y = 600, xt = -7.1337144915014505, p = 2265.732571016997, a = 319719.77130509913, r = 0.8881104758474976
x = 545.147310802713, y = 600, xt = 5.1473108027130365, p = 2290.294621605426, a = 327088.3864816278, r = 0.9085788513378551
x = 538.7105683563277, y = 600, xt = -1.2894316436722875, p = 2277.4211367126554, a = 323226.3410137966, r = 0.8978509472605462
x = 516.2962767295539, y = 600, xt = -23.703723270446062, p = 2232.592553459108, a = 309777.76603773236, r = 0.8604937945492566
x = 514.8046711226925, y = 600, xt = -25.195328877307475, p = 2229.609342245385, a = 308882.8026736155, r = 0.8580077852044875
x = 534.1744352015667, y = 600, xt = -5.825564798433334, p = 2268.3488704031333, a = 320504.66112094, r = 0.8902907253359444
x = 547.8497329051606, y = 600, xt = 7.849732905160636, p = 2295.6994658103213, a = 328709.8397430964, r = 0.9130828881752677
x = 543.9860105514526, y = 600, xt = 3.9860105514526367, p = 2287.9720211029053, a = 326391.6063308716, r = 0.9066433509190878
x = 556.5075480262749, y = 600, xt = 16.50754802627489, p = 2313.01509605255, a = 333904.52881576493, r = 0.9275125800437914
x = 547.4846170167439, y = 600, xt = 7.484617016743869, p = 2294.9692340334877, a = 328490.7702100463, r = 0.9124743616945731
x = 542.9808599757962, y = 600, xt = 2.980859975796193, p = 2285.9617199515924, a = 325788.5159854777, r = 0.9049680999596603
x = 558.1431346363388, y = 600, xt = 18.1431346363388, p = 2316.2862692726776, a = 334885.8807818033, r = 0.9302385577272313
x = 557.7623278019018, y = 600, xt = 17.762327801901847, p = 2315.5246556038037, a = 334657.3966811411, r = 0.9296038796698364
x = 565.9123415942304, y = 600, xt = 25.912341594230384, p = 2331.8246831884608, a = 339547.40495653823, r = 0.943187235990384
x = 587.1231290278956, y = 600, xt = 47.12312902789563, p = 2374.2462580557913, a = 352273.8774167374, r = 0.978538548379826
x = 596.1921920767054, y = 600, xt = 56.192192076705396, p = 2392.384384153411, a = 357715.31524602324, r = 0.9936536534611756
x = 599.0806587506086, y = 600, xt = 59.08065875060856, p = 2398.161317501217, a = 359448.39525036514, r = 0.9984677645843476
x = 599.1503421100788, y = 600, xt = 59.15034211007878, p = 2398.3006842201576, a = 359490.20526604727, r = 0.9985839035167979
x = 583.600834524259, y = 600, xt = 43.60083452425897, p = 2367.201669048518, a = 350160.5007145554, r = 0.9726680575404316
[Finished in 0.1s]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment