[feedback/help requested] A practical introduction to kill-safe, concurrent programming in Racket

I’ve written a long tutorial exploring the user of Racket’s Concurrent ML (CML) inspired concurrency paradigm to write an API wrapping git-cat-file. It is meant to serve as an introduction to kill-safety and CML concurrency, while assuming some existing knowledge of Racket or other Schemes. I found that there weren’t a lot of resources beyond the reference documentation that explained how to put these APIs together, and I hope this can fill that hole.

Beyond any feedback about the writing itself, one request for help: Is there a way to make the links to Racket standard forms correctly link to docs.racket-lang.org, instead of being red squiggles? That would really increase the value of Scribble generating all those links. Thanks!

I'll post it to a wider audience soon.

https://nikhilism.com/writing/racket-concurrency/

4 Likes

Assuming you use (require (for-label racket)) etc, run scribble like this:

scribble --htmls ++xref-in setup/xref load-collections-xref --dest $TARGET \
         --redirect-main "http://docs.plt-racket.org/" \
         cml-tutorial.scrbl 
1 Like
  • the match regexp pattern can be written with or using and to bind the match: (and message (or "missing" "ambiguous"))
  • in the reader response, I’d probably do something like for/first + a rem function, though your single pass approach is reasonable:
(define found
  (findf (lambda (p) (equal? got-key (Pending-key p))) pending))
(define new-pending
  (if found (remove found pending) pending))
(loop … (if found (cons (pending->response found contents)  response-attempts) response-attempts) …)

The for/first would allow me to put pending->response in the loop, but then remove would be less concise (you’d need to remf and check for got-key again).

1 Like

Thanks for the tip! I found that using +m (when using Racket 8.9) instead of the xref stuff was enough. To get a single HTML file, my command was:

raco scribble --html +m --redirect-main "https://docs.racket-lang.org/" --dest <path> --dest-name index.html scribblings/git-catter.scrbl

Thank you for the match tip!
For the filter, I will stick with my current approach.

For the filter question in section 5.2, i would use for/fold:

(define-values (new-pending found)
  (for/fold ([new-pending '()]
             [found #f]
             #:result (values (reverse new-pending) found))
            ([p (in-list pending)])
    (cond
      [(and (not found) (equal? got-key (Pending-key p)))
       (values new-pending
               (pending->response p contents))]
      [else
       (values (cons p new-pending)
               found)])))