Должен ли IO работать в режиме реального времени во время распространения? - PullRequest
1 голос
/ 08 мая 2019

Я пытаюсь написать библиотеку FRP в Идрисе.Эта библиотека предназначена для работы в среде с одним потоком.Будущее реализовать Monad и Align.Я хочу реализовать функции с этими упрощенными сигнатурами типов:

createFutureResolveLater : (Future a, a -> IO ()) -- later time

createFutureResolveNow : a -> IO (Future a) -- current time

pure : a -> Future a -- before everything

align : Future a -> Future a -> Future (These a b) -- min of two times

join : Future (Future a)) -> Future a -- max of two times

exeEvent : Future (IO a) -> IO (Future a) -- ??

simultaneous : Future a -> Future b -> Future Bool -- min of two times

subFuture : Future a -> (a -> IO ()) -> IO ()

Мне кажется очевидным, что

simultaneous a a, simultaneous a (fmap f a), etc.

должно быть будущим, которое переходит в истину.

В

do
    oe <- exeEvent ie
    let s = simultaneous oe ie
    ...

должен ли s принимать значение true?

В реактивном-банане s будет ложным.См. MapEventIO в http://hackage.haskell.org/package/reactive-banana-1.2.1.0/docs/Reactive-Banana-Frameworks.html

В рефлексах s также, скорее всего, будет ложным.См. ExecuteEvent в https://daig.github.io/reflex/Reflex-PerformEvent-Class.html

Почему эти авторы библиотек выбирают s как false?

1 Ответ

1 голос
/ 08 мая 2019

Попытка выяснить, что вы спрашиваете. Я думаю, вы задаетесь вопросом, как учесть IO действия, которые требуют времени, нет? Потому что если бы действие IO было мгновенным, это не было бы вопросом. Хотя у меня все еще есть вопрос, что делает блок действия IO, пока не наступит будущее, или он планирует его асинхронно?

Если это неблокирующий вызов, я бы сказал, что он должен дождаться завершения действия IO. (Я бы также назвал это schedFuture или что-то подобное, чтобы было ясно, что он не блокируется.) В противном случае у вас может быть случай, когда Future находится в прошлом, но значение все еще недоступно, которые могут испортить логику функций, которые объединяют события и т. д.

Если это блокирующий вызов, я бы вместо этого предоставил

waitFuture :: Future a -> IO a

и позволить пользователю иметь дело с остальными (например, они могут fmap (const x) в исходном будущем, если они хотят сохранить время, они могут использовать now :: IO (Future ()), если они хотят, когда оно завершится, и т. Д.). Возможно, стоит предложить комбинаторы для них, если вы можете придумать для них хорошие имена, иначе они настолько просты, что я просто выбью.

Я также обнаружил, что при создании подобных систем полезно различать «1018» действия и действия, которые могут блокироваться. Я предполагаю, что это параллельно различию javascript между асинхронными и обычными вызовами стека. Есть много нечетких вопросов, подобных этому, и соответствующие очевидные ответы, как правило, зависят от этого различия.

...