Julias Reactive.jl Bibliothek ist entworfen, um Reactive programming in Julia zu ermöglichen. Die Crux ist, dass nur Signale reaktiv sind, und sie sind entweder unabhängig oder abhängig von anderen Signalen. Im Beispiel ist x
ein unabhängiges Signal und die Standardaktualisierung für das Signal ruft push!
auf. z
ist abhängiges Signal auf x
, weshalb es automatisch aktualisiert wird, wenn sich x
ändert.
Nun sind dies die einzigen beiden Signale. Beachten Sie, dass c
als Vector()
definiert ist, was kein Signal, sondern ein normales Array in Julia ist. Jeder Code, der darauf ausgeführt wird, funktioniert nur einmal wie alle nicht reaktiven Sprachen. Deshalb
for i in dar
push!(x, i)
push!(c, value(z))
end
wird nur c
einmal vergeben, wenn der Code zum ersten Mal ausgeführt wird, wobei z
noch den Standardwert 500
aufgrund init=500
im Code hält. Dies macht einen intuitiven Sinn. In der Tat wird, wenn c
aufgrund geändert z
, dann haben wir das zugrunde liegende Verhalten von Julia gemacht zu reaktiv, und dies ist flüchtig und so ist unerwünscht ...
Also, wie machen wir c
Updates, wenn z
tut? Der korrekte Weg ist, die reaktive Programmierung vollständig zu verwenden, und so sollte c
ein abhängiges Signal von z
sein. Da c
den Zustand z
beibehält, ist das korrekte Konstrukt in der reaktiven Programmierung foldp
, was für "falten über vergangene Werte" steht.
Ein Code, der funktioniert, ist die folgende: -
using Reactive
x = Signal(100)
z = map(v -> v + 500, x)
c = foldp((acc, value) -> push!(acc, value), Int[], z)
for i in rand(90:110, 10)
push!(x, i)
yield() #Can also use Reactive.run_till_now()
println(value(z))
end
@show value(c)
Sie c
erhalten die Array aller vorherigen Werte von z
(mit Ausnahme der Anfangswert durch Wahl zu sein, wenn Sie also den Anfangswert wollen auch das kann leicht gemacht werden). Beachten Sie, dass die reaktive Programmierung eine ähnliche Codekomplexität beibehält, jedoch die reaktive Fähigkeit hinzufügt. Dies macht den Code eleganter und einfacher zu pflegen.
Mit yield()
oder Reactive.run_till_now()
ist wie im Kommentar empfohlen, so werde ich über die Erklärung skim. Aber meine Meinung ist, dass, wenn Sie das tun müssen, Sie wahrscheinlich reaktive Programmierung nicht richtig verwenden, oder Ihr Problem wird anderen Paradigma besser passen.
Dies ist, wie ich schreiben würde: -
using Reactive
x = Signal(100)
z = map(x) do v
result = v + 500
println(result)
return result
end
c = foldp(Int[], z) do acc, value
push!(acc, value)
end
for i in rand(90:110, 10)
push!(x, i)
end
@show value(c)
Beachten Sie, dass der reaktive Teil der Beschreibung selbst ist. Jetzt z
druckt sich selbst, wenn es aktualisiert wird, die beschreibende statt zwingend ist. Obwohl das Update asynchron ist, erfassen wir dennoch ein Update auf z
. Der imperative Code des Schiebens zu x
ist von selbst, Sachen modular haltend. Der Code ist hoch genug und leicht zu lesen, ohne Routinefunktionen wie yield()
in einem solchen High-Level-Skript.
Es ist keine Antwort, aber das Hinzufügen von 'yield()' zwischen 'push!' S ist eine minimale Änderung, die die Dinge funktionieren lässt. Die Aktualisierung von 'z's Wert geschieht in einer anderen Aufgabe. –
Anstelle von 'yield()' verwende 'Reactive.run_till_now()' nach dem 'push!' Zum Signal. Dieser Tipp ist von https://github.com/JuliaLang/Reactive.jl/issues/99 –
Das funktioniert, danke. Das scheint nicht so zu sein, aber das macht mehr Sinn. – pyrex