Arie van Wingerden writes:

> Hi Christopher,
>
> 2018-05-11 15:31 GMT+02:00 Christopher Lemmer Webber <cweb...@dustycloud.org:
>
>>
>> In comparison to Syndicate, Goblins is less a new language and more a
>> lightweight library for actors that interfaces nicely with "#lang
>> racket" type code
>> ​..
>>
>
> For me personally Goblin would be the better choice I think.​

If you do think that's the case (again, with the warning that it's
pre-alpha), I'd encourage you to look at the goblins/demos/ directory
for some examples.  But here is the main API:

racket@> (require goblins)

;; Spawning an actor from a procedure
racket@> (define counting-actor
           (spawn
            (let ([counter 0])
              (lambda ()
                (set! counter (+ counter 1))
                (format "I've been called ~a times" counter)))))

;; this sends a message, but we don't get a response...
;; "fire and forget"
racket@> (<- counting-actor)

;; this sends a message, but we do wait for a response...
;; "resume the continuation with a response"
racket@> (<<- counting-actor)
"I've been called 2 times"

;; Note that doing <<- outside an actor context will block the current
;; thread until a response comes in.  Doing <<- within an actor will
;; stuff this into a queue we're "waiting on responses" from, but
;; the actor will robustly continue to respond to messages.

;; We can also spawn Racket's classes as actors fairly easily:
racket@> (define greeter%
           (class object%
             (super-new)
             (define/public (greet name)
               (string-append "Hello, " name "!"))))
;; And we can send messages to their public methods
racket@> (<<- (spawn-new greeter%) 'greet "Bert")
"Hello, Bert!"

;; Actors are shut down when all references to them are garbage
;; collected, so we don't need to worry about doing a one-off
;; spawn as we did above.

;; Subclassing of course works too.
racket@> (define groucher%
           (class greeter%
             (super-new)
             (init [annoyed-by "my back"])
             (define am-annoyed-by annoyed-by)
             (define/override (greet name)
               (string-append "Grumble grumble... "
                              (super greet name)
                              "... "
                              am-annoyed-by " is irritating me..."))))
racket@> (<<- (spawn-new groucher%
                         [annoyed-by "your hair"])
              'greet "Grover")
"Grumble grumble... Hello, Grover!... your hair is irritating me..."

;; Here's a more complex example that demonstrates using our own address
;; with (self)
racket@> (let* ([narrator
                 (spawn
                  (lambda (msg)
                    (displayln msg)))]
                [gossiper
                 (spawn-new (class object%
                              (super-new)
                              (define listeners '())
                              (define/public (subscribe address)
                                ;; We don't care about the order of this
                                ;; so fire and forget
                                (<- narrator "gossiper> Got a new subscriber!")
                                (set! listeners (cons address listeners)))
                              (define/public (spread-gossip msg)
                                (<- narrator
                                    (format "gossiper> Spreading juicy gossip: 
~a"
                                            msg))
                                (for ([listener listeners])
                                  (<- listener 'receive-gossip msg)))))]
                [listener%
                 (class object%
                   (super-new)
                   (init name)
                   (define our-name name)
                   (define/public (start-listening)
                     ;; We're going to wait here because we don't want to return
                     ;; until this completes
                     ;; (self) is our own actor address and is bound dynamically
                     ;; in a message handling context
                     (<<- gossiper 'subscribe (self)))
                   (define/public (receive-gossip msg)
                     (<- narrator
                         (format "~a> Ooh, I just heard that ~a"
                                 our-name msg))))]
                [sam (spawn-new listener% [name "sam"])]
                [pat (spawn-new listener% [name "pat"])])
           (<<- sam 'start-listening)
           (<<- gossiper 'spread-gossip "Tim has great hair")
           (<<- pat 'start-listening)
           (<<- gossiper 'spread-gossip "Samantha has a nice car"))
gossiper> Got a new subscriber!
gossiper> Spreading juicy gossip: Tim has great hair
sam> Ooh, I just heard that Tim has great hair
gossiper> Got a new subscriber!
gossiper> Spreading juicy gossip: Samantha has a nice car
pat> Ooh, I just heard that Samantha has a nice car
racket@> sam> Ooh, I just heard that Samantha has a nice car

;; In fact you can see on that last one that since talking to the
;; gossiper is asynchronous with <-, it clobbered my racket prompt ;)

====== End tutorial ======

Hope that was interesting!
As you can see, it tries very hard to look a lot like racket code.
I used to have addresses even be callable as if
(address args ...) was implicitly the same as (<<- address args)
but since Goblins actors are "robust", I didn't want people to be
surprised that their actors may respond to other messages while waiting
for replies to their continuation with <<-.
But when I had it like that it didn't even look like message passing,
just normal procedure calls, which in a way was fun :)

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to