Непрерывное переключение сигнала в FRP со стрелками

Я играл с библиотеками Arrowized FRP в Haskell (в частности, Yampa), но я не могу понять, как сделать «постоянное» переключение. Под этим я подразумеваю, что сигнал проходит через сигнальную функцию (sf ниже), которая сама является сигналом (как показано в верхней половине изображения).

Постоянное переключение

Поскольку я заранее не знаю, какими будут параметры переключателя, я не вижу, как свести его к более простому двоичному переключателю.

Как же тогда это сделать, если это вообще возможно? Я бы предпочел код Yampa, но меня устраивает любой код Arrowized FRP. Я не пробовал другие библиотеки (например, Sodium или Reactive Banana), чтобы узнать, будет ли у меня такая же путаница в этих случаях, но мне они тоже интересны.

ИЗМЕНИТЬ

Чтобы сделать это более ясным и конкретным, я пометил изображение; Возможные типы меток:

  • в: Either Int (Int -> Int)

  • 1: (Int -> Int) -> (Either Int (Int -> Int) -> (Int -> Int))

  • sf может быть:

(Either Int (Int -> Int) -> (Int -> Int)) -> Either Int (Int -> Int) -> (Int -> Int)

(например, app). Но это только в том случае, если часть, помеченная знаком вопроса, представляет вход в sf. Если он представляет более сложный переключатель, тип будет

(Either Int (Int -> Int) -> (Int -> Int)) -> (Int -> Int)

вместо.

  • 2 и out практически не имеют значения.

Идея состоит в том, что я хочу, чтобы схема вела себя как если бы sf была app, с сигналом, помеченным f, представляющим функцию, которая применяется к in, и с самим in, являющимся источником обоих аргументов для fs. , и сами f. Я хочу получить схему, которая может обрабатывать входные данные и динамически изменять свое поведение (сигнальные функции, которые его составляют) на основе этих входных данных.

С одной стороны, мне кажется, что sf на самом деле не может быть app, так как в данном случае у нас нет ArrowApply; но, с другой стороны, я полагаю, что такое же поведение может быть достигнуто с помощью некоторой формы сложного переключения.


person user2141650    schedule 18.11.2013    source источник
comment
Прежде чем появится кто-то знающий, я просто предложу наивный подход: ArrowLoop дает ли вам то, что вы хотите?   -  person Tom Ellis    schedule 18.11.2013
comment
Я вижу, как это было бы, если бы SF был экземпляром ArrowApply, но в остальном я не сразу вижу, как это помогает.   -  person user2141650    schedule 20.11.2013
comment
Не могли бы вы указать тип sf (а также то, что выглядит как два Arrow в сочетании с &&&)? Думаю, это помогло бы мне понять, что происходит.   -  person Tom Ellis    schedule 20.11.2013
comment
Я отредактировал вопрос - дайте мне знать, если это все еще неясно.   -  person user2141650    schedule 21.11.2013


Ответы (2)


Я все еще думаю, что это случай ArrowLoop!

У тебя есть

in :: Arr () A
sf :: Arr (A -> B, A) B
one :: Arr B (A -> B)
two :: Arr B C

sf это всего лишь arr (uncurry ($)).

Тогда у вас есть sf >>> (one &&& two) :: Arr (A -> B, A) (A -> B, C), и вы можете использовать loop (или, скорее, loop с разумно расположенным arr swap), чтобы получить Arr A C.

Даст ли это вам то, что вы хотите?

person Tom Ellis    schedule 20.11.2013
comment
Ага! Во-первых, спасибо за выбор лучших типов, чем я. Во-вторых, я думаю, что вижу здесь смысл. Я как-то не догадался замкнуть петлю по большей схеме (sf >>> (one &&& two)). Но, похоже, ты прав. loop $ arr swap >>> (sf >>> (one &&& two)) >>> arr swap имеет правильный тип, и все проверяет тип. Я почти уверен, что это идеальный ответ на вопрос, но дайте мне еще несколько минут, чтобы убедиться. - person user2141650; 21.11.2013
comment
Большой! Вернитесь с дополнительными вопросами, если у вас есть какие-либо. - person Tom Ellis; 21.11.2013

Вы просите, чтобы стрелка, выводимая стрелкой, использовалась как стрелка. Вот для чего нужен app из ArrowApply.

Если вы хотите использовать это в какой-то циклической конструкции, такой как ваша диаграмма, вам может понадобиться ArrowLoop, но на самом деле нотация do в любом случае позволяет вам быть довольно гибким со всеми этими вещами.

В этом ответе есть довольно длинное объяснение app, но я скопирую основной соответствующий бит:


Что конкретно делает приложение? его тип даже не имеет (->). Он позволяет вам использовать вывод стрелки как стрелку. Посмотрим на тип.

app :: ArrowApply m => m (m b c, b) c

Я предпочитаю использовать m вместо a, потому что m больше похоже на вычисление, а a на значение. Некоторым людям нравится использовать оператор типа (конструктор инфиксного типа), поэтому вы получаете

app :: ArrowApply (~>) => (b ~> c, b) ~> c

Мы думаем о b ~> c как о стреле, и мы думаем о стреле как о вещи, которая берет bс, делает что-то и дает cс. Таким образом, это означает, что app — это стрелка, которая принимает стрелку и значение и может дать значение, которое первая стрелка произвела бы на этом входе.

У него нет -> в сигнатуре типа, потому что при программировании со стрелками мы можем превратить любую функцию в стрелку, используя arr :: Arrow (~>) => (b -> c) -> b ~> c, но вы не можете превратить каждую стрелку в функцию, поэтому (b ~> c, b) ~> c можно использовать там, где (b ~> c, b) -> c или (b -> c, b) ~> c не будет. .

person some guy    schedule 18.11.2013
comment
SF не является и не может быть превращен в экземпляр ArrowApply. - person user2141650; 20.11.2013