6

我试图了解这种函数式反应式编程是如何工作的,但我遇到了一个问题。我正在尝试创建一个boid 模拟,但我开始的速度很慢,我现在已经将一个 boid 定义为一个函数,它采用一个起始位置并创建一个从一个位置到一个位置的信号函数,其中输入是点它正在移动,输出是当前位置:

type Position2 = Vector2 Float

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

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

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

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

这里 aBoid 向点 (500, 500) 寻找,而 bBoid 向 aBoid 寻找。

我的问题是,当我希望这两个 boids 互相寻找时。当我这样做时:

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 东西非常困难并且经常令人困惑,所以我不确定我是否有道理;)

4

2 回答 2

3

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

怎么样:

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

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

(.)(如果您使用的翻转版本来想象,管道可能更容易理解(>>>)。)

于 2011-12-27T22:02:04.583 回答
2

因此,在 ehird 的一点帮助下,我想出了一些可行的方法。

代码如下(这里使用 3 个 boid 而不是 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而不是loopi 可以给每个 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)

WhererandomBoids num生成num随机的 boid。

于 2011-12-28T12:53:08.290 回答