f(x) == f(x)
Equational Reasoning
Abstract Algebra
The Monad and the Monoid
Mutants
var x = 1
...
x = 2
Effects
readByte() != readByte()
/**Mutable variable in state thread S containing a value of type A.
http://research.microsoft.com/en-us/um/people/simonpj/papers/lazy-functional-state-threads.ps.Z
*/
sealed trait STRef[S, A] {
protected var value: A
/**Reads the value pointed at by this reference. */
def read: ST[S, A] = returnST(value)
/**Modifies the value at this reference with the given function. */
def mod[B](f: A => A): ST[S, STRef[S, A]] = st((s: Tower[S]) => {
value = f(value);
(s, this)
})
...
class Diff(other: Actor) extends Actor {
var last: Option[Int] = None
def act = loop {
react {
case i: Int =>
last match {
case Some(`i`) =>
case _ => other ! i; last = Some(i)
}
case _ => ???
}
}
}
the bodies are not functions and actor programming is not functional
var last: Option[Int] = None
messages, channels and actor bodies are not typed! enough said
case i: Int => ...
case _ => ???
actors don't compose. the wiring is baked into the actor bodies
class Diff(other: Actor) extends Actor { ... }
tricky to change connection topology in flight
poor support for message joins - needed for any topology beyond trees
old school actors coud do this:
react {
case Right(b) => react {
case Left(a) => // got both an A and a B
}
}
A and B can arrive in either order
poor support for flow control - you need to design your own mini communication protocols
val print = new Printer
val diff = new UglyDiff(print)
val emit = new Emitter(200, diff)
print.start
diff.start // diff can overrun the mailbox of print
emit.start // emit can overrun the mailbox of diff
Futures, async iteratees etc.
(but connection topology is limited)
Functional Reactive Programming
(but glitches vs. synchronous operation)
Clustered stream processors (Storm) and CEP systems?
object diff extends Actor {
val input = Input[Int](6)
val output = Output[Int]()
def start: Action = input react {
i => output(i) { ready(i) }
}
def ready(last: Int): Action = input react {
case `last` => ready(last)
case i => output(i) { ready(i) }
}
run(start, 1)
}
Note
emit.output --> diff.input; diff.output --> print.input
diff.error --> supervisor.input
Note
Github:
https://github.com/arnolddevos/FlowActors
Slides:
http://notes.backgroundsignal.com/Actor_Discussion.html
@a4dev