Fighting with FRP
Fighting with FRP
我读过关于FRP的文章,非常兴奋。它看起来很棒,所以你可以写更多的高级代码,一切都更容易组合,等等。
然后我试着用几百个sloc重写我自己的小游戏,从普通的js到培根。
我发现,我并没有只写高级逻辑代码,而是用Bacon.js及其对原则的坚持来击败它。
我遇到了一些头痛,主要是干扰干净的代码
.take(1)
我应该创造丑陋的建筑,而不是获得价值。
- 循环依赖项
有时它们应该符合逻辑。但在FRP中实施它是可怕的
- 活动状态
即使是bacon.js的创建者也有麻烦。
这里的例子是代码的和平来证明这个问题:
任务是不允许两个玩家呆在同一个地方
使用bacon.js 实现
http://jsbin.com/zopiyarugu/2/edit?js,控制台
function add(a) {return function(b){return a + b}}
function nEq(a) {return function(b){return a !== b}}
function eq(a) {return function(b){return a === b}}
function always(val) {return function(){return val}}
function id(a){return a}
var Player = function(players, movement, initPos){
var me = {};
me.position = movement
.flatMap(function(val){
return me.position
.take(1)
.map(add(val))
})
.flatMap(function(posFuture){
var otherPlayerPositions = players
.filter(nEq(me))
.map(function(player){return player.position.take(1)})
return Bacon
.combineAsArray(otherPlayerPositions)
.map(function(positions){
return !positions.some(eq(posFuture));
})
.filter(id)
.map(always(posFuture))
})
.log('player:' + initPos)
.toProperty(initPos);
return me;
}
var moveA = new Bacon.Bus();
var moveB = new Bacon.Bus();
var players = [];
players.push(new Player(players, moveA, 0));
players.push(new Player(players, moveB, 10));
moveA.push(4);
moveB.push(-4);
moveA.push(1);
moveB.push(-1);
moveB.push(-1);
moveB.push(-1);
moveA.push(1);
moveA.push(-1);
moveB.push(-1);
我想展示的是:
me.positions
有其自身的依赖性- 理解这段代码并不容易。这是当务之急。它看起来更容易理解。我花了更多的时间在培根的实现上。结果,我不确定它是否会像预期的那样工作
我的问题:
也许我错过了一些基本的东西。也许我的实施方式不是FRP风格的?
也许这个代码看起来不错,只是不习惯新的编码风格?
还是这个众所周知的问题,我应该选择万恶之中的至善?所以FRP的问题就像所描述的,或者OOP的问题。
我在尝试用Bacon和RxJs编写游戏时也有过类似的经历。有自我依赖性的事情(比如球员的位置)很难用"纯FRP"的方式处理。
例如,在我早期的Worzone游戏中,我包含了一个可变目标对象,可以查询玩家和怪物的位置。
另一种方法是像Elm一样:将整个游戏状态建模为单个属性(或Elm中称之为Signal),并根据该完整状态计算下一个状态。
到目前为止,我的结论是FRP不太适合游戏编程,至少在"纯粹"的方式上是这样。毕竟,对于某些事情来说,可变状态可能是更容易组合的方法。在一些游戏项目中,比如Hello World Open赛车赛,我使用了可变状态,比如用于存储状态的DOM和用于传递事件的EventStreams。
所以,Bacon.js不是一颗银弹。我建议你自己找出,在哪里应用FRP,在哪里不应用!
我有时也会有类似的填充。对我来说,使用FRP编程的经验主要是解决难题。其中有些很容易,有些则不然。而那些我觉得容易的事情可能对我的同事来说更难,反之亦然。我不喜欢玻璃钢。
别误会我的意思,我喜欢解谜,这很有趣!但我认为付费工作的编程应该更。。。没趣的更可预测。代码应该尽可能简单明了,甚至是原始代码。
当然,全局可变状态也不是我们应该走的路。我认为我们应该想办法让玻璃钢更无聊:)
还有一点关于你的代码的评论,我认为这将是更FRP’ish(一个未经测试的草案):
var otherPlayerPositions = players
.filter(nEq(me))
.map(function(player){return player.position});
otherPlayerPositions = Bacon.combineAsArray(otherPlayerPositions);
me.position = otherPlayerPositions
.sampledBy(movement, function(otherPositions, move) {
return {otherPositions: otherPositions, move: move};
})
.scan(initPos, function(myCurPosition, restArgs) {
var myNextPosition = myCurPosition + restArgs.move;
if (!restArgs.otherPositions.some(eq(myNextPosition))) {
return myNextPosition;
} else {
return myCurPosition;
}
});
- Fighting with FRP
- issue with FB.Event.subscribe
- geolocation-marker.js conflict with markerclusterer.js
- Angular 2.0 with JavaScript or TypeScript?
- 为什么不推荐使用“with”?是否有更好或其他方法可以“下降”到对象的命名空间
- WebComponentsJS with IE10
- 指令的模板必须只有一个根元素:With restrict E&替换true
- timeago.js with datatable and PHP
- Ajax and Json with Rails
- errors with Javascript try catch
- how to split a string with ','
- Understanding Javascript scope with "var that = this&qu
- FRP 中 EventStreams 的循环依赖关系
- Architecture for CPU intensive tasks with NodeJS & Socke
- How to declare a Map containing certain properties with flow
- 设置'这'在React with Inverse Data Flow中
- Unit-testing multiple use cases with Karma & Mocha.js
- Modify Javascript with C#
- 谷歌地图API v3:Initial View is Fine,but Gray Box with No Map if
- Using jQuery with classes from ES6