防止Yampa / Animas中的无限循环与SF相互依赖

时间:2011-12-27 21:12:24

标签: haskell frp yampa

我正在努力了解这种功能性反应式编程是如何工作的,而且我遇到了一个问题。我正在尝试创建一个boid simulation,但我开始慢慢地,我现在已经定义了一个boid作为一个函数,它采取一个起始位置并创建一个从一个位置到一个位置的信号函数,其中输入它是朝着它移动的点,输出是当前的位置:

type Position2 = Vector2 Float

boid :: Position2 -> SF Position2 Position2
boid s = loop (arr (uncurry seek) >>> integral >>> arr (^+^ s) >>> arr dup)

搜索功能需要两个输入(因为循环)。当前位置和目标位置。然后它只是创建一个从当前位置指向目标位置的矢量,其幅度为50,即速度。然后积分速度并添加起始位置。最后,信号被分成两部分,因此一个可以成为输出,另一个可以循环回到搜索功能。

现在我可以像这样定义boids:

aBoid = constant (vector2 500 500) >>> (boid (vector2 600 60))
bBoid = aBoid >>> (boid (vector2 3 4))

这里aBoid寻求点(500,500)并且bBoid寻求aBoid。

我的问题是,当我想让两个小船向对方寻求时。当我这样做时:

aBoid = bBoid >>> (boid (vector2 600 60))
bBoid = aBoid >>> (boid (vector2 3 4))

程序只打印:ProgramName: <<loop>>我认为这意味着它会进入无限循环。

我也尝试过这样的par函数:

sim :: SF a [Position2]
sim = loop (arr snd >>> par route [boid (vector2 10 10), boid (vector2 100 100)] >>> arr dup)

这里route函数只是将每个boid的输出映射到另一个boid的输出(如zip,但偏移量为1)

这也会提供<<loop>>消息。

我认为在处理反应系统时,让对象依赖于彼此的状态应该是一个非常常见的问题,所以我希望有一些优雅的解决方案。

我应该补充一点,我发现这个FRP的事情非常困难并经常令人困惑,所以我不确定我是否有意义;)

2 个答案:

答案 0 :(得分:3)

我对Yampa / Animas并不熟悉,但似乎问题本质上是你有一个没有基本情况的递归;你已经描述了系统的 evolution ,但不是它是如何开始的。

怎么样:

aBoid = bBoid >>> boid (vector2 600 60) >>> iPre (vector2 0 0)
bBoid = aBoid >>> boid (vector2 3 4)

以便aBoid从(0,0)开始,然后反馈循环在下一瞬间开始?这是假设我对iPre的理解是正确的......

(如果您想象(.)(>>>)的翻转版本,可能会更容易理解。

答案 1 :(得分:2)

所以在ehird的帮助下,我想出了一些有用的东西。

代码如下(这里使用3个boids而不是2个):

sim :: SF a [Position2]
sim = loopPre [zeroVector, zeroVector, zeroVector] (
    arr snd >>>
    par route [boid (vector2 10 10), boid (vector2 100 400), boid (vector2 500 500)] >>>
    arr dup)

此处路线功能与我在问题中描述的功能相同。

使用loopPre代替loop我可以为每个boid提供一个起始位置,从而解决问题。我认为ehird的解决方案不起作用的原因是,当并行运行多个信号函数时需要一些管道,par函数需要处理。

一位100%肯定会发生什么事的人的回答将不胜感激:)

修改

sim的这种实现有点漂亮:

sim :: Int -> SF a [Position2]
sim num = loopPre (take num (repeat zeroVector)) (
    arr snd >>>
    par route (randomBoids num) >>>
    arr dup)

randomBoids num生成num随机boids的位置。