Запутался в схемах выключателей Yampa
Вот некоторые схемы выключателей Yampa по адресу:
http://www.haskell.org/haskellwiki/Yampa/switch
http://www.haskell.org/haskellwiki/Yampa/rSwitch
http://www.haskell.org/haskellwiki/Yampa/kSwitch
(и так далее).
Я обнаружил, что switch
Единственная диаграмма с описанием - самая простая для понимания. Другие, кажется, трудно следовать аналогичным символам, чтобы прочитать диаграммы. Например, чтобы попытаться прочитать rSwitch
с символами, используемыми в switch
может быть:
Будьте рекурсивным SF, который всегда получает сигнал типа "in" и возвращает сигнал типа "out". Начните с начального SF того же типа, но кто-то за пределами функции переключения (квадрат?[Cond])) может также передать новый SF через Событие (тип
Event (SF in out)
в подписи), в то время как условие выполнено (для '?' перед квадратом [cond]). В случае события Yampa будет использовать новый SF вместо существующего. Этот процесс является рекурсивным, поскольку '?' (не может получить это из диаграммы, за исключением того, что подпись rSwitch кажется рекурсивной).
И после того, как я смотрю в источник rSwitch
Похоже, это использовать switch
переключиться на тот же инициал SF рекурсивно, пока t
срабатывает (в соответствии с тем, что описано на диаграмме, хотя я не вижу, что особенное t
будет запущен в исходном коде).
В аркаде Yampa это объясняет dpSwitch
с кодом и примером. И статья об игре "Frag" также использует dpSwitch
, Тем не менее rSwitch
кажется, отсутствует в этих уроках. Так что я действительно не знаю, как использовать r-
или k-
последовательные коммутаторы, и в каких случаях они нам понадобятся.
1 ответ
Все switch
функции - это способы изменить сигнальную функцию так, чтобы она вела себя как другая сигнальная функция. Я лично нахожу, что диаграммы Yampa довольно сложно анализировать, но сигнатуры типов различных переключателей дают хорошее представление о том, как их понимать. Как только вы понимаете сигнатуры типов, диаграммы становятся намного понятнее. switch
само по себе самое основное:
switch :: SF a (b, Event c) -> (c -> SF a b) -> SF a b
Если мы посмотрим на тип, он говорит нам точно, что он делает: он берет SF sf
и генератор SF sfg
, sf
производит значения типа (b, Event c)
и вход к генератору функции сигнала также имеет тип c
, Итак, всякий раз, когда sf
Когда происходит событие, SF переключится на результат генератора SF. Пока событие не произойдет, результирующий SF будет возвращать значение исходного SF.
Эта идея также используется в rswitch
а также kswitch
варианты, но немного по-другому.
rswitch
: Это называется "внешним переключателем", что означает, что SF переключится без какого-либо анализа своего входа или выхода. Давайте посмотрим на тип подписи:
rswitch :: SF a b -> SF (a, Event (SF a b)) b
Требуется один SF, который принимает в качестве входных значений типа a
и выводит значения типа b
, rswitch
создает новый SF, который также производит вывод b
, но принимает дополнительный ввод типа Event (SF a b)
, Обратите внимание, что тип значения Event соответствует типу ввода. Это означает, что всякий раз, когда происходит событие, этот SF переключается на это значение события. Тем не менее, тип SF остается SF (a, Event (SF a b)) b
, Это означает, что SF может получать дополнительные события с новыми SF, что будет влиять на поведение всего SF. Одним из применений этого может быть поведение ИИ в игре:
moveFollowTarget :: SF TargetPosition Velocity
moveShootTarget :: SF TargetPosition Velocity
moveIdle :: SF TargetPosition Velocity
aiMovement :: SF (TargetPosition, Event (SF TargetPosition Velocity)) Velocity
aiMovement = rswitch moveIdle -- Initially idle...
aiMovementManager :: SF a (Event (SF TargetPosition Velocity))
aiMovementManager = ... whatever ...
Здесь aiMovementManager
будет запускать событие всякий раз, когда нужно изменить поведение движения ИИ, и значением события будет SF, на который должно измениться движение.
kswitch
: Это известно как intrinsic switch
, поскольку содержимое SF анализируется, чтобы выяснить, каким должен быть правильный переключатель. Давайте рассмотрим тип подписи
kswitch :: SF a b -> SF (a, b) (Event c) -> (SF a b -> c -> SF a b) -> SF a b
Вот, kswitch
принимает три аргумента, sf
, analyzer
, а также mapping
, sf
это просто стандартный SF с входами типа a
и выходы типа b
, sf
как сигнал ведет себя изначально. analyzer
это SF, который принимает на вход и выход sf
и может или не может запустить какое-то событие, значение которого имеет тип c
, Если не происходит событие, то ничего не происходит, и SF продолжает вести себя как sf
, Если он запускает событие, то оба sf
и значение события передается mapping
который определяет новую SF для переключения. kswitch
полезно при изменении поведения систем в зависимости от их результатов.
Одним из примеров, где это полезно, является алгоритм предотвращения перегрузки TCP. Здесь мы смотрим, теряем ли мы сетевые пакеты или увеличиваем или уменьшаем скорость, с которой мы запрашиваем данные.