2016-10-08 8 views
2

Я изучаю Мартин Одерски Principles of Reactive Programming. Говоря о реализации простой структуры FRP, он вначале дал команду, которая использует StackableVariable (т. Е. DynamicVairable), чтобы отслеживать текущий обновленный сигнал, который я могу понять. Но в конце слайдов он упомянул, что более чистым решением является использование неявного параметра вместо DynamicVariable. Может ли кто-нибудь показать мне, как это можно сделать?Как реализовать FRP с использованием неявного параметра?

+0

Я думаю, что scala.rx делает это следующим образом: https://github.com/lihaoyi/scala.rx/ blob/master/scalarx/shared/src/main/scala/rx/Core.scala – Reactormonk

+0

ссылка, похоже, не работает, я получаю сообщение об отказе доступа –

ответ

3

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

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

val a: Signal[Int] = ??? 
val b: Signal[Int] = ??? 
val xPlusY: Signal[Int] = Signal(a() + b()) 

Здесь, когда a() называется, она добавляет себя в список зависимостей в настоящее время оценки сигнала. Поскольку эта информация недоступна где-либо еще, мы в основном используем глобальную переменную a.k.a.

У этого решения есть несколько проблем. Например, мы также можем позвонить a(), если мы не внутри Signal(). Кроме того, мы должны использовать глобальную переменную.

Решения будет давать эту информацию a() через неявный аргумент: Меняет подпись от

Signal[T]#apply(): T 

в

Signal[T]#apply()(implicit triggeredBy: Signal[_]) 

(Обратите внимание, что мы, вероятно, хотим использовать некоторые новый тип TriggeredBy, который инкапсулирует сигнал)

Таким образом, реализация этого метода будет иметь доступ к i ts, генерирующий сигнал без глобальной/потоковой локальной переменной.

Но теперь мы должны каким-то образом представить это неявное. Одним из вариантов является также изменить сигнатуру функции сигнал создания из

def Signal.apply[T](fun: => T): Signal[T] 

в

def Signal.apply[T](fun: Signal[_] => T): Signal[T] 

К сожалению, синтаксис нашего примера кода должен изменить то, потому что мы должны обеспечить функцию вместо тела:

val xPlusY: Signal[Int] = Signal { implicit triggeredBy => a() + b() } 

Есть несколько способов решения этой проблемы:

  • Подождите, пока не будут реализованы неявные типы функций 2. Это, вероятно, не произойдет в ближайшее время, но это позволит нам написать Signal.apply подпись следующим образом:

    def Signal.apply[T](fun: implicit Signal[_] => T): Signal[T] 
    

    и затем иметь возможность написать Signal(a() + b()) снова.

  • Использование макрома магии для преобразования кода формы Signal(a() + b()) в код Signal.internalApply(implicit triggeredBy => a() + b()). Это означает, что Signal.apply теперь является макросом. Это путь, по которому идет scala.rx 3, и он хорошо работает с точки зрения использования. Это также позволяет нам снова написать Signal(a() + b()).

Update: обновлена ​​ссылка на неявной функции объяснения к более детальному блога artikle

+0

Непонятная функция типа вещей, похоже, делает что-то странное в примере Odersky. Вы уверены, что он также будет работать так, как вы его используете? –

+0

ну, так как вся моя информация об этом - от просмотра https://youtu.be/GHzWqJKFCk4?t=47m19s, и я не нашел никакой дополнительной информации об этом, и она нигде не будет реализована; Я не уверен, что это также будет работать в этом примере, но я понимаю, что он, по крайней мере, должен работать таким же образом. –

+1

@ Jasper-M есть новая статья в блоге Мартина Одерски, в которой четко указано, что неявные типы функций действительно будут работать как ожидалось (но, к сожалению, только в пунктире); Я обновил ссылку в статье –

 Смежные вопросы

  • Нет связанных вопросов^_^