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

And*_*iid 6 haskell frp yampa

我试图理解这个功能反应式编程是如何工作的,我遇到了一个问题.我正在尝试创建一个boid模拟,但是我开始慢慢地,我现在已经定义了一个boid作为一个起始位置并从一个位置到一个位置创建信号函数的函数,其中输入是点它正在走向,输出是当前位置:

type Position2 = Vector2 Float

boid :: Position2 -> SF Position2 Position2
boid s = loop (arr (uncurry seek) >>> integral >>> arr (^+^ s) >>> arr dup)
Run Code Online (Sandbox Code Playgroud)

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

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

aBoid = constant (vector2 500 500) >>> (boid (vector2 600 60))
bBoid = aBoid >>> (boid (vector2 3 4))
Run Code Online (Sandbox Code Playgroud)

这里aBoid寻求点(500,500)和bBoid寻求aBoid.

我的问题是,当我想要两个boid相互寻求时.当我这样做:

aBoid = bBoid >>> (boid (vector2 600 60))
bBoid = aBoid >>> (boid (vector2 3 4))
Run Code Online (Sandbox Code Playgroud)

该程序只是打印:ProgramName: <<loop>>我假设它意味着它进入无限循环.

我也试过使用这样的par函数:

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

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

这也给出了<<loop>>信息.

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

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

And*_*iid 2

因此,在第三者的帮助下,我想出了一些可行的方法。

代码如下(这里使用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)
Run Code Online (Sandbox Code Playgroud)

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

通过使用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)
Run Code Online (Sandbox Code Playgroud)

其中randomBoids num生成num随机群体。

  • 顺便说一句,`采取 n 。重复` == `复制n` :) (2认同)