我试图理解这个功能反应式编程是如何工作的,我遇到了一个问题.我正在尝试创建一个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的事情非常困难而且经常令人困惑,所以我不确定我是否真的有意义;)
因此,在第三者的帮助下,我想出了一些可行的方法。
代码如下(这里使用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随机群体。