On Mon, May 21, 2018 at 11:21 AM Jay McCarthy <jay.mccar...@gmail.com>

> This is very cute! Can you point to a fun example? I looked through
> the repo and it wasn't obvious where some tests and examples were.
> Jay

Here's a variety of small examples.

Sometimes, I just want to wait until a bunch of stuff is done:

  > (sync
       (for/list ([i 10])
         (thread (λ () (channel-put ch i))))
       (for/list ([_ 10])
         (thread (λ () (write (channel-get ch))))))))

Sometimes, I want to do something more than once:

  > (define (channel-dup-evt cs v)
      (async-void* (map (curryr channel-put-evt v) cs)))

With some background getters,

  > (define cs (build-list 5 (λ _ (make-channel))))
  > (for ([c cs] [i 5])
      (thread (λ () (writeln (cons i (channel-get c))))))

it's ready for synchronization.

  > (sync (channel-dup-evt cs 'X))
  (1 . X)
  (3 . X)
  (0 . X)
  (2 . X)
  (4 . X)

The natural numbers:

  > (define nats
      (let ([n 0]) (pure (begin0 n (set! n (add1 n))))))

This event acts like a generator.

  > (sync nats)
  > (sync nats)
  > (sync nats)

nats is handy for generating indices and unique keys in bulk through

  > (sync (event-list* (make-list 4 nats)))
  '(3 4 5 6)

It's always fun to implement the fibonacci sequence:

  > (define (naive-fib n)
      (case n
        [(0) (pure 0)]
        [(1) (pure 1)]
        [else (fmap + (naive-fib (- n 1)) (naive-fib (- n 2)))]))

Of course, the naive implementation is very slow.

  > (time (sync (naive-fib 29)))
  cpu time: 5826 real time: 5831 gc time: 1004

This one:

  > (define fib
      (let ([a 1] [b 0])
        (pure (begin0 b (set!-values (a b) (values (+ a b) a))))))

is much faster.

  > (time (last (sync (event-list* (make-list 30 fib)))))
  cpu time: 1 real time: 1 gc time: 0

nats and fib can be combined to build an index:

  > (define fibs (make-hash))
  > (sync
      (make-list 30 (fmap (curry hash-set! fibs) nats fib))))
  > (hash-ref fibs 29)
  > (hash-ref fibs 15)

Promises are pretty easy, too:

  > (define (promise thunk)
      (define result #f)
      (bind (thread (λ ()
                      (define vs (call-with-values thunk list))
                      (set! result (pure (apply values vs)))))
            (λ _ result)))

The results are memoized so multiple syncs don't replay side effects.

  > (define p (promise (λ () (writeln 123) 4)))
  > (sync p)
  > (sync p)

My personal favorite is more practical than fun:

  > (define (dispatch m ms [default void-mediator])
      (define (dispatch-put m0)
         (λ _ (λ (k . vs) (say* (hash-ref ms k default) vs m0)))))
      (event-let ([m0 (accept m)]) (offer m0 (dispatch-put m0))))

Without getting into what mediators are, this one forwards a message from m
an element of hash ms. If the message is a list and the first element is a
of ms, the rest of the message is delivered to the keyed element. The
event may finish before the message is delivered, but the sender and
are guaranteed to synchronize on each other. Getting this right was hard.

Most of my work with event-lang is in solving hairy synchronization problems
like this, so I felt I should sneak one in.


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