Thespis is a threaded actor library for Common Lisp.
With Ultralisp installed:
(ql:quickload :thespis)
;; name state args
(define-actor counter ((i 0)) (increment)
(sleep 1)
(incf i increment))
(let ((actor (counter))) ; spawn a counter actor
(send actor 2) ; returns instantly
(ask actor 1) ; returns 3 after 2 seconds
(close-actor actor)) ; cleanup
In this example, we define a prototype of a counter actor, this defines a function of the same name that will spawn an instance of this actor and lets us define slots for it to store state in, and arguments for messages sent to the actor.
If you try this in your REPL you will notice that `send` is asynchronous, it enqueues a message for the actor and returns instantly. The `ask` function is synchronous and waits for its message to be processed and returns the result of the actor’s processing.
Here is a little pong example, I might add a more convenient way to communicate with singleton actors:
(define-actor pinger () (c)
(format t "~a: ping!~%" c)
(sleep 0.2)
(if (< c 10)
(send :ponger (1+ c))
(progn (close-actor :ponger)
(close-actor :pinger))))
(define-actor ponger () (c)
(format t "~a: pong!~%" c)
(sleep 0.2)
(if (< c 10)
(send :pinger (1+ c))
(progn (close-actor :ponger)
(close-actor :pinger))))
;; Spawn global named actors
(pinger :name :pinger)
(ponger :name :ponger)
(send :ponger 0)
TODO