我正在努力了解这种功能性反应式编程是如何工作的,而且我遇到了一个问题。我正在尝试创建一个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的事情非常困难并经常令人困惑,所以我不确定我是否有意义;)
答案 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的位置。