Preventing endless loops in Yampa / Animas with SF depending on each other

I am trying to understand how this functional reactive programming works, and I ran into a problem. I am trying to create a boid simulator , but I am starting slowly, and for now I have defined boid as a function, starting a position and creating a signal function from a position to a position where the input is the point to which it is moving and the output is the current position:

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

the search function accepts two inputs (due to the loop). Current position and target position. Then he simply creates a vector pointing from the current position to the target position with a value of 50, i.e. speed. Then the speed is integrated and the starting position is added. At the end, the signal is divided into two, so you can become the output, and the other can return to the search function.

Now I can define boids as follows:

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

Here aBoid tends to the point (500, 500), and bBoid tends to aBoid.

My problem is when I want two bunks looking for each other. When I do this:

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

The program simply prints: ProgramName: <<loop>> , which I assume means that it goes into an infinite loop.

I also tried using the par function as follows:

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

here the route function simply maps the output of each boid to the input of another (e.g. zip , but with an offset of 1)

This also gives the message <<loop>> .

I think that the presence of objects depends on each other's state, should be a fairly common problem when working with reactive systems, so I hope that there are several elegant solutions.

I must add that I find this FRP thing very difficult and often confusing, so I'm not sure that I even make sense at all;)

+6
source share
2 answers

So, with a little help from ehird, I came up with something that works.

The code is as follows (here 3 boids are used instead of 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) 

Here the route function works in the same way as described in the question.

Using loopPre instead of loop , I can give each boid a starting position that solves the problem. I think the reason why the ehird solution didn’t work was because some plumbing is required when running several signal functions in parallel, which the par function takes care of.

The answer from a person who is 100% sure what is happening will be appreciated :)

Edit

This sim implementation is a bit prettier:

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

Where randomBoids num generates random boids num .

+2
source

I am not very familiar with Yampa / Animas, but it seems that the problem is that you have recursion without base code; You described the evolution of the system, but not how it begins.

What about:

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

so aBoid start with (0,0) and then the feedback loop starts the next moment? This suggests that my understanding of iPre correct ...

(A conveyor may be easier to understand if you represent it using (.) , An inverted version (>>>) .)

+3
source

Source: https://habr.com/ru/post/904555/


All Articles