Создайте сигнал из списка

Можно ли создать Signal из List? По сути, я хочу что-то с подписью List a -> Signal a. Я знаю, что Signal представляет изменяющееся во времени значение, и поэтому что-то подобное на самом деле не имеет никакого смысла (т.е. я не могу придумать причину для использования его в производственном коде).

Однако я мог видеть его применение для тестирования. Например, представьте себе некоторую функцию, которая зависит от прошлых значений Signal (через foldp, например), и вы хотели сделать утверждения о состоянии системы, учитывая, что сигнал получил значения x, y и z.

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


person robertjlooby    schedule 26.07.2015    source источник


Ответы (2)


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

import Time
import Graphics.Element exposing (show)

list = [1..10]


signalFromList : List a -> Signal a
signalFromList list =
  let
    (Just h) =
      List.head list

    time =
      Time.every Time.second

    maybeFlatMap =
      flip Maybe.andThen

    lists =
      Signal.foldp (always <| maybeFlatMap List.tail) (Just list) time
  in
    Signal.filterMap (maybeFlatMap List.head) h lists

main = Signal.map show <| signalFromList list

Однако!

Не должно быть сложно провести тестирование без сигналов. Если у вас где-то есть foldp, в тесте вы можете вместо этого использовать List.foldl над списком [x,y,z]. Это должно дать вам возможность посмотреть состояние вашей программы после ввода x, y, z.

person Apanatshka    schedule 26.07.2015

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

Тогда возникает вопрос: можем ли мы сделать это нативно?

f : List a -> Signal a

Я часто думаю о (Сигнале а) как об «а, который меняется со временем». Здесь мы предоставляем список as и хотим, чтобы функция со временем меняла его для нас.

Прежде чем мы пойдем дальше, я рекомендую бегло взглянуть на Native/Signal.js: https://github.com/elm-lang/core/blob/master/src/Native/Signal.js

Скажем, мы спускаемся на родину со своим Листом Ас. Нам нужно что-то вроде Signal.constant, но с некоторым дополнительным поведением, которое «отправляет» каждый a после. Когда же мы сможем сделать отправку? Я предполагаю, что мы не можем сделать это во время функции построения сигнала, так как мы все еще строим график сигнала. Это оставляет нам несколько других вариантов:

  • что-то отвратительное с setTimeout, планирование отправки каждого 'a' в соответствующий момент в будущем
  • разработка хука в среде выполнения elm, чтобы мы могли запускать произвольный обратный вызов в точке, когда сигнальный граф полностью построен

По крайней мере, для меня первое звучит подвержено ошибкам, и я надеюсь, что второго не существует (и никогда не будет)!

Для тестирования ваше предложение использовать складку списка для имитации поведения foldp было бы тем, что я бы сделал.

person grumpyjames    schedule 26.07.2015
comment
хех, да оба эти варианта звучат довольно ужасно. Не то чтобы мой signalFromList был намного лучше, потому что вы застряли с этим сигналом времени, отсчитывающим время без всякой причины после того, как вы очистили список. - person Apanatshka; 28.07.2015