def doc: List[String]
def doc: List[String]
doc.foreach { s =>
$("#editor").append(s) }
def doc: List[String]
doc.foreach { s =>
$("#editor").append(s) }
def doc: List[String]
doc.foreach { s =>
$("#editor").append(s) }
def doc: List[String]
doc.foreach { s =>
$("#editor").append(s) }
def doc: List[String]
doc.foreach { s =>
$("#editor").append(s) }
def doc: List[String]
doc.foreach { s =>
$("#editor").append(s) }
def time: Events[Int]
Event stream
def time: Events[Int]
time.onEvent { t =>
doc.foreach { s =>
$("#editor").append(s) }
}
List
exists somewhere
Events
happens sometime
onEvent
~ foreach
time.onEvent(t => renderHtml())
Events.filter
~ List.filter
val frame: Events[Int] =
time.filter(t % 16 == 0)
0, 1, 2, 3, ..., 16, 17, 18, ..., 32, ...
0 16 32
Events.map
~ List.map
val keys: Events[(Boolean, Char)]
val presses: Events[Char] =
keys.filter(_._1).map(pc => pc._2)
When, exactly, is sometime?
As most UI toolkits,
event propagation is single-threaded.
Event streams are an abstraction for
concurrent - occurring at the same time
asynchronous - not occurring at the same time
val frame =
time.filter(_ % 16 == 0)
frame.onEvent(render)
Asynchronicity without concurrency is convenient.
Decouples components in the system, and prevents data races.
Concurrency is another useful property.
time.onEvent(render)
Reactor {
time.onEvent(render)
}
Reactor {
time.onEvent(render)
keys.map(_._2).onEvent(update)
}
Reactor {
time.onEvent(render)
keys.map(_._2).onEvent(update)
}
Reactor {
time.onEvent(render)
keys.map(_._2).onEvent(update)
}
Reactor {
time.onEvent(render)
keys.map(_._2).onEvent(update)
}
Reactor {
time.onEvent(render)
keys.map(_._2).onEvent(update)
}
val server:
Channel[(Id, Channel[List[String]])]
val (updates, updatechan) = open[List[String]]
updates.onEvent { newDoc =>
doc = newDoc
}
server ! (docId, updatechan)
Broadcast
Communication pattern in which the sender sends the same message to multiple targets.
insert((i1, x1), insert((i0, x0), doc))
=
insert((i0, x0), insert((i1, x1), doc))
import replication.crdt