worldcomponent
worldtimestream
のコンセプトを継承したライブラリです。
https://github.com/kenokabe/timeengine
https://www.npmjs.com/package/timeengine
timeengine
Time Engine is the True Functional Reactive Programming (FRP) Library from the Point of View of Physics, our World and Time
The World, Time, Physics, Mathematics, Equations, and Functional Reactive Programming
JavaScriptで時間発展する物理系=私達が生活するこの宇宙の挙動を、関数型プログラミングでイミュータブルに記述する、という関数型リアクティブプログラミング(FRP)の概念実証から再掲/
時間発展する物理系、つまり、私達が生活するこの宇宙の挙動を、関数型プログラミングでイミュータブルに記述する、という関数型リアクティブプログラミング(FRP)の概念実証をJavaScript言語でしてみましょう。
我々の馴染みの深い「放物線」を例に取ります。
「放物線を描く」と日常的によく使いますが、物理学(日本語)では正確には、「斜方投射」と言います。
斜方投射(しゃほうとうしゃ)とは物体をある初速度をもって空中に投げ出す動作である。空気抵抗が十分小さく無視できる場合、斜方投射された物体の軌跡は放物線を描く
水平方向にx軸、
鉛直上向きにy軸をとります。
初速
偏角
のとき、
斜方投射してからの経過時間 における
物体の速度および座標 は
という恒等式で表せます。(は 重力加速度=9.8 m/ss)
これがニュートン物理学の時間発展する恒等式です。
. タイガー・ウッズの平均ヘッドスピード57.5m/s ボール初速度85.0~86.5m/sと公表されています。らしいですから、
初速を85.0m/s、偏角30度とし、空気抵抗を無視したゴルフのスーパーショットっぽい斜方投射を上記時間発展する恒等式をそのまま用いて、
timeengine
React
を利用して関数型リアクティブプログラミングのコードを書くと以下のようになります。//MKS system of units
var V0 = 85.0; // m/s
var DEG = 30; //degree
var THETA = DEG / 180 * Math.PI; //radian
var G = 9.8; //gravity const
//10msec time resolution
//t seconds elapsed since t0
var t = __.intervalSeq(10).tMap((tt, t0) => (tt - t0) / 1000);
var x = t.tMap((t) => V0 * Math.cos(THETA) * t);
var y = t.tMap((t) => V0 * Math.sin(THETA) * t - 1/2
* G * Math.pow(t, 2));
The full code is represented at the bottom of this document.Live Demo
http://sakurafunctional.github.io/demo/react-physics/Basic
The only API you get to know istMap
.tMap
maps a time-sequence to another time-sequence.Time Engine is all about
tMap
.Reactive Programming in JavaScript
var x = __(); // time sequence
var y = x.tMap((x) => x * 2); // y = x * 2
x.t = 3;
console.log(x.t); //3
console.log(y.t); //6
x.t = 5;
console.log(x.t); //5
console.log(y.t); //10
Declarative code like Math equation and Single (no duplicate) update by automatic dependency resolution
var a = __();
var b = __([a]).tMap(([a]) => a * 2); // b.t = 1 * 2 = 2
var c = __([a, b]).tMap(([a, b]) => a + b * 3); // c.t = 1 + 2 * 3 = 7
var d = __([b]).tMap(([b]) => b * 100); // d.t = 2 * 100 = 200
var e = __([a, b, c, d]).tMap(([a, b, c, d]) => a + b + c + d); //210
a.t = 1; // a is updated, and the whole equations will be evaluated.
Atomic update using Promise
var atomic = __([a, b, c, d, e])
.tMap(([a, b, c, d, e]) => ({
a,
b,
c,
d,
e
}));
var timeseq10 = atomic.tMap((val) => {
__.t = __.log('atomic', val);
});
Promise
var m = __();
var n = __();
var o = __();
var p = __([m, n, o]).tMap(() => 'Promised');
var timeseq15 = __.timeoutSeq(6000)
.tMap(() => m.t = 'some');
var timeseq16 = __.timeoutSeq(7000)
.tMap(() => n.t = 'time');
var timeseq17 = __.timeoutSeq(8000)
.tMap(() => o.t = 'other');
var timeseq18 = __.timeoutSeq(10000)
.tMap(() => m.t = 'some');
var timeseq19 = __.timeoutSeq(11000)
.tMap(() => n.t = 'time');
var timeseq20 = __.timeoutSeq(12000)
.tMap(() => o.t = 'other');
var timeseq21 = m.tMap((m) => {
__.t = __.log({
m
});
});
var timeseq22 = n.tMap((n) => {
__.t = __.log({
n
});
});
var timeseq23 = o.tMap((o) => {
__.t = __.log({
o
});
});
var timeseq24 = p.tMap((p) => {
__.t = __.log({
p
});
});
Install
node / io.js
$ npm install timeengine
WebBrowser
ES5 native
includehttps://github.com/kenokabe/timeengine/blob/master/timeengine.js
then
<script type="text/javascript" src="./timeengine.js"></script>
ES6 with Babel transpiler
https://babeljs.io/include
https://github.com/kenokabe/timeengine/blob/master/babel-browser.js
https://github.com/kenokabe/timeengine/blob/master/timeengine.jsx
then
<script src="./babel-browser.js"></script>
<script type="text/babel" src="./timeengine.jsx"></script>
Test
$ npm test
equivalent to$ babel timeengine.jsx -o timeengine.js; babel-node test.jsx
test.jsx
(() => {
'use strict';
var __ = require('./timeengine.js');
__.t = __.log('test.jsx started...');
//Reactive and Declarative code ===============
var x = __(); // time sequence
var y = x.tMap((x) => x * 2); // y = x * 2
x.t = 3;
console.log(x.t); //3
console.log(y.t); //6
x.t = 5;
console.log(x.t); //5
console.log(y.t); //10
/*
//comment out, dependency Error occures here
//since y depends on x, this is an illegal operation
y.t = 100;
console.log('>>>>>>>>>>>>>>>>>>>>>>>>>>>>>' + x.t);
console.log('>>>>>>>>>>>>>>>>>>>>>>>>>>>>>' + y.t);
*/
//store values on timeStamps ==============
var i = __(true); //store flag = true
var j = __([i], true).tMap(() => i.t * 2); // j = i * 2
i.t = 3;
console.log(j.t); //6
i.t = 5;
console.log(j.t); //10
// seq can be operated just like vanilla JavaScript Array
__.t = __.log('i.length', i.length);
i.map((val) => {
__.t = __.log('i.t', val); // 3, 5
});
j.map((val) => {
__.t = __.log('j.t', val); //6, 10
});
var timestamp_i0 = i.TimestampOnIndex(0);
var timestamp_i1 = i.TimestampOnIndex(1);
var timestamp_j0 = j.TimestampOnIndex(0);
var timestamp_j1 = j.TimestampOnIndex(1);
__.t = __.log(i.T(timestamp_i0)); //3
__.t = __.log(i.T(timestamp_i1)); //5
__.t = __.log(j.T(timestamp_j0)); //6
__.t = __.log(j.T(timestamp_j1)); //10
//==============================================
//------------------------
var timeseq0 = __
.timeoutSeq(500, true) // store === true
.tMap((t) => {
__.t = __.log('--------------------------------------------');
return t;
});
var timeseq1 = timeseq0.tMap((t) => {
__.t = __.log('timeseq0.t', t);
__.t = __.log('stored to arrray', timeseq0[0]); // same val
//stored to the seq array
});
var f = (tt, t0) => {
__.t = __.log('t0', t0);
__.t = __.log('tt', tt);
};
var timeseq2 = __.timeoutSeq(1000).tMap(f);
var timeseq3 = __.timeoutSeq(2000).tMap(f);
//------------------------
var timeseq4 = __.timeoutSeq(2500)
.tMap(__.log('-------------------------------------------'));
// Single (no duplicate) update by dependency analysis
var a = __();
var b = __([a]).tMap(([a]) => a * 2); // b.t = 1 * 2 = 2
var c = __([a, b]).tMap(([a, b]) => a + b * 3); // c.t = 1 + 2 * 3 = 7
var d = __([b]).tMap(([b]) => b * 100); // d.t = 2 * 100 = 200
var e = __([a, b, c, d]).tMap(([a, b, c, d]) => a + b + c + d); //210
var timeseq5 = a.tMap((a) => {
__.t = __.log({
a
});
});
var timeseq6 = b.tMap((b) => {
__.t = __.log({
b
});
});
var timeseq7 = c.tMap((c) => {
__.t = __.log({
c
});
});
var timeseq8 = d.tMap((d) => {
__.t = __.log({
d
});
});
var timeseq9 = e.tMap((e) => {
__.t = __.log({
e
});
});
// Atomic update using build-in Promise mechanism
var atomic = __([a, b, c, d, e])
.tMap(([a, b, c, d, e]) => ({
a,
b,
c,
d,
e
}));
var timeseq10 = atomic.tMap((val) => {
__.t = __.log('atomic', val);
});
var timeseq11 = __.timeoutSeq(3000)
.tMap(() => a.t = 1);
var timeseq12 = __.timeoutSeq(3500)
.tMap(__.log('--------------------------------------------'));
var timeseq13 = __.timeoutSeq(4500)
.tMap(() => a.t = 5);
//---------------------------------------------
var timeseq14 = __.timeoutSeq(5000)
.tMap(__.log('--------------------------------------------'));
//Promise---------------------------------------------
var m = __();
var n = __();
var o = __();
var p = __([m, n, o]).tMap(() => 'Promised');
var timeseq15 = __.timeoutSeq(6000)
.tMap(() => m.t = 'some');
var timeseq16 = __.timeoutSeq(7000)
.tMap(() => n.t = 'time');
var timeseq17 = __.timeoutSeq(8000)
.tMap(() => o.t = 'other');
var timeseq18 = __.timeoutSeq(10000)
.tMap(() => m.t = 'some');
var timeseq19 = __.timeoutSeq(11000)
.tMap(() => n.t = 'time');
var timeseq20 = __.timeoutSeq(12000)
.tMap(() => o.t = 'other');
var timeseq21 = m.tMap((m) => {
__.t = __.log({
m
});
});
var timeseq22 = n.tMap((n) => {
__.t = __.log({
n
});
});
var timeseq23 = o.tMap((o) => {
__.t = __.log({
o
});
});
var timeseq24 = p.tMap((p) => {
__.t = __.log({
p
});
});
var timeseq25 = __.timeoutSeq(13000)
.tMap(__.log('--------------------------------------------'));
var f99 = () => {
__.t = __.log('Any Event Function can be wrapped.');
};
__.t = __.wrap(setTimeout)(f99, 14000);
//onMousemove or whatever instead of setTimeout
///-----------------------------------------------
var timeseq26 = __.timeoutSeq(15000)
.tMap(() => {
__.t = __.log('--------------------------------------------');
var timeseq27 = __
.intervalSeq(1000)
.tMap((tt, t0) => (tt - t0) / 1000)
.tMap((tt) => {
__.t = __.log(tt);
return tt;
});
});
})();
result
> babel timeengine.jsx -o timeengine.js; babel-node test.jsx
test.jsx started...
3
6
5
10
6
10
i.length 2
i.t 3
i.t 5
j.t 6
j.t 10
3
5
6
10
--------------------------------------------
timeseq0.t 1440134670777
stored to arrray 1440134670777
t0 1440134670277
tt 1440134671278
t0 1440134670277
tt 1440134672277
-------------------------------------------
{ c: 7 }
{ e: 210 }
atomic { a: 1, b: 2, c: 7, d: 200, e: 210 }
{ d: 200 }
{ b: 2 }
{ a: 1 }
--------------------------------------------
{ c: 35 }
{ e: 1050 }
atomic { a: 5, b: 10, c: 35, d: 1000, e: 1050 }
{ d: 1000 }
{ b: 10 }
{ a: 5 }
--------------------------------------------
{ m: 'some' }
{ n: 'time' }
{ p: 'Promised' }
{ o: 'other' }
{ m: 'some' }
{ n: 'time' }
{ p: 'Promised' }
{ o: 'other' }
--------------------------------------------
Any Event Function can be wrapped.
--------------------------------------------
1.002
2.004
3.006
4.007
5.008
React Physics Test
index.jsx
/*global React __ */
(() => {
'use strict';
//MKS system of units
var V0 = 85.0; // m/s
var DEG = 30; //degree
var THETA = DEG / 180 * Math.PI; //radian
var G = 9.8; //gravity const
//10msec time resolution
//t seconds elapsed since t0
var t = __.intervalSeq(10).tMap((tt, t0) => (tt - t0) / 1000);
var x = t.tMap((t) => V0 * Math.cos(THETA) * t);
var y = t.tMap((t) => V0 * Math.sin(THETA) * t - 1/2 * G * Math.pow(t, 2));
//==============================================================
var Drawscale = 4; //4 dot = 1 meter
class ReactComponent extends React.Component {
constructor() {
super();
var timeseq = __([x, y])
.tMap(([x, y]) => [50 + x * Drawscale, 300 - y * Drawscale])
.tMap(([x, y]) => {
this.rx = x;
this.ry = y;
this.forceUpdate();
});
}
render() {
var el = (
<div>
<h1>For new shot, Just Reload the browser page</h1>
<svg height = "100%" width = "100%">
<circle r="5" fill="blue"
cx = {this.rx}
cy = {this.ry}/>
</svg>
</div>
);
return el;
};
}
var mount = React.render(<ReactComponent/>, document.body);
})();
0 コメント:
コメントを投稿