Предотвращение бесконечных петель в Yampa / Animas с SF в зависимости друг от друга - PullRequest
6 голосов
/ 28 декабря 2011

Я пытаюсь понять, как работает это функциональное реактивное программирование, и я столкнулся с проблемой.Я пытаюсь создать симуляцию boid , но я начинаю медленно, и на данный момент я определил 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.

Моя проблема в том, когда я хочу, чтобы два 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 на вход другого (например, zip, но со смещением 1)

Это также дает сообщение <<loop>>.

Я думаю, что наличие объектов зависит от состояния друг друга, должно быть довольно распространенной проблемой при работе с реактивными системами, поэтому я надеюсь, что есть какое-то элегантное решение.

Я должен добавить, что я нахожу эту вещь FRP очень трудной и часто сбивающей с толку, поэтому я не совсем уверен, вообще ли я вообще что-то понимаю;)

Ответы [ 2 ]

3 голосов
/ 28 декабря 2011

Я не очень знаком с Yampa / Animas, но, похоже, проблема в том, что у вас рекурсия без базового варианта;Вы описали эволюцию системы, но не то, как она начинается.

Как насчет:

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

, так что aBoid начинается с (0,0), а затем цикл обратной связи начинается в следующий момент?Это предполагает, что мое понимание iPre правильное ...

(Конвейер может быть легче понять, если представить его с помощью (.), перевернутой версии (>>>).)

2 голосов
/ 28 декабря 2011

Итак, с небольшой помощью от 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.

...