Miscellaneous Utilities
Jan Dvořák <mordae@anilinux.org>
1 Syntax Extensions
(require misc1/syntax) | package: misc1 |
syntax
(producing ((name value) ...) body ...)
syntax
(using ((name value) ...) body ...)
> (using ((variable 40) (coefficient -13)) (printf "result = ~s\n" (add1 (* variable coefficient)))) result = -519
syntax
(when* ((name value) ...) body ...)
syntax
(recursive (name ...) body ...)
> (recursive (a b) (values 1 2))
1
2
> ((recursive (fact) (λ (n) (if (= 0 n) 1 (* n (fact (sub1 n)))))) 5) 120
syntax
(loop body ...)
syntax
(while continue? body ...)
syntax
(until halt? body ...)
syntax
(loop-while-cond (test body ...) ...)
> (loop-while-cond ((< (random) 0.2) (display "jackpot!\n")) ((< (random) 0.7) (display "hit!\n")))
hit!
hit!
hit!
jackpot!
hit!
syntax
(loop-until-cond (test body ...) ...)
> (loop-until-cond ((> (random) 0.5) (display "pressure too high!")) ((> (random) 0.3) (display "boiler cracking!")) ((> (random) 0.1) (display "office is a pressure coo...!"))) office is a pressure coo...!
syntax
(with-semaphore sema body ...)
> (let ((sema (make-semaphore 1))) (with-semaphore sema 'protected)) 'protected
syntax
(spawn-thread body ...)
> (thread-wait (spawn-thread 'do-something))
syntax
(with-output-bytes body ...)
> (with-output-bytes (write-byte 64)) #"@"
syntax
(with-input-bytes bstr body ...)
> (with-input-bytes #"hello" (read-byte)) 104
syntax
(with-output-string body ...)
> (with-output-string (write-byte 64)) "@"
syntax
(with-input-string str body ...)
> (with-input-string "hello" (read-byte)) 104
syntax
(after body ... (cleanup cleanup-body ...))
syntax
(when-defined name body ...)
> (when-defined replace-evt 'have-replace-evt) 'have-replace-evt
> (when-defined frobnicate 'have-frobnication)
> (when-defined foldl 'have-folds) 'have-folds
2 Match Expanders
(require misc1/match) | package: misc1 |
syntax
(hash-lookup (key value) ...)
> (match #hasheq((temperature . 34) (day-time . "afternoon")) ((hash-lookup ('temperature te) ('day-time dt)) (format "beautiful ~a, ~a°C" dt te))) "beautiful afternoon, 34°C"
3 Dictionaries
(require misc1/dict) | package: misc1 |
The optional default keyword argument allows to define a substitute for mising keys’ values. If a procedure is specified, it’s return value is used.
> (dict-mref (hasheq 'apples 4 'pears 2) 'apples 'pears)
4
2
> (dict-mref (hasheq 'pomelos 1) 'peaches #:default 0) 0
procedure
(dict-merge base other ...) → dict?
base : dict? other : dict?
> (dict-merge (hasheq 'apples 1) '((pears . 2))) '#hasheq((apples . 1) (pears . 2))
procedure
(dict-merge! base other ...) → void?
base : dict? other : dict?
syntax
(let-dict (((name ...) value) ...) body ...)
> (let-dict (((a b c) (hasheq 'a 1 'b 2 'c 3)) ((d e f) '((d . 4) (e . 5) (f . 6)))) (+ a b c d e f)) 21
4 Lists
(require misc1/list) | package: misc1 |
procedure
(list->values lst) → any
lst : list?
> (list->values '(1 2 3))
1
2
3
> (values* 1 '(2 3))
1
2
3
procedure
(split-every lst idx) → (listof list?)
lst : list? idx : exact-positive-integer?
> (split-every '(1 2 3 4 5 6) 2) '((1 2) (3 4) (5 6))
> (for/list ((part (split-every '(1 2 3 4 5 6) 3))) (apply + part)) '(6 15)
syntax
(let-list (((name ...) value) ...) body ...)
5 Exceptions
(require misc1/throw) | package: misc1 |
Raise the resulting exception.
> (struct exn:fail:example exn:fail (number))
> (throw (exn:fail:example 42) 'example "failed to understand" "subject" "universe and everything") example: failed to understand
subject: universe and everything
6 Asynchronous Tasks
(require misc1/async) | package: misc1 |
This module provides a simple way to run a piece of code in a background thread, getting it’s result back via Racket’s integrated event system.
procedure
(async-task proc) → evt?
proc : (-> any)
> (define result-evt (async-task (λ () (sleep 1/10) 42)))
> (sync/timeout 1/20 result-evt) #f
> (sync/timeout 1/20 result-evt) #f
> (sync/timeout 1/20 result-evt) 42
syntax
(async body ...)
7 Fast Channels
(require misc1/fast-channel) | package: misc1 |
Fast channels are an alternative to racket/async-channel that makes use of semaphores instead of a background thread, yielding a much greater throughput.
procedure
> (define channel (make-fast-channel))
procedure
(fast-channel? v) → boolean?
v : any/c
> (fast-channel? channel) #t
procedure
(fast-channel-put channel value ...) → void?
channel : fast-channel? value : any/c
There is no limit on number of items placed into a channel and the caller is never blocked.
> (fast-channel-put channel 'carrot)
> (fast-channel-put channel 'apple)
> (fast-channel-put channel 'rose 'and 'cherry)
procedure
(fast-channel-get channel) → any
channel : fast-channel?
> (fast-channel-get channel) 'carrot
> (sync channel) 'apple
procedure
(fast-channel-try-get channel) → any
channel : fast-channel?
Please note that it is possible to send multiple values, but this function fails with just one. Make sure you expect proper return arity.
> (fast-channel-try-get channel)
'rose
'and
'cherry
> (fast-channel-try-get channel) #f
procedure
(fast-channel-peek channel) → any
channel : fast-channel?
> (fast-channel-put channel 42)
> (fast-channel-peek channel) 42
procedure
(fast-channel-try-peek channel) → any
channel : fast-channel?
> (fast-channel-try-peek channel) 42
> (fast-channel-get channel) 42
> (fast-channel-try-peek channel) #f
procedure
(fast-channel-peek-evt channel) → evt?
channel : fast-channel?
> (let ((peek-evt (fast-channel-peek-evt channel))) (fast-channel-put channel 'hello) (sync peek-evt)) 'hello
> (fast-channel-get channel) 'hello
8 Events
Extended events, some building on the new replace-evt procedure when available.
(require misc1/evt) | package: misc1 |
procedure
(recurring-evt base-evt [handler]) → evt?
base-evt : evt? handler : procedure? = void
> (let ((channel (make-async-channel))) (for ((i 3)) (async-channel-put channel i)) (sync (alarm-in-evt 1000) (recurring-evt channel (λ (item) (printf "item ~s\n" item)))))
item 0
item 1
item 2
#<alarm-evt>
procedure
(alarm-in-evt msecs) → evt?
msecs : real?
procedure
(constant-evt arg ...) → evt?
arg : any/c
> (sync (constant-evt 1 2 3))
1
2
3
> (define parent-evt (wrap-evt always-evt (λ _ (printf "parent producing 42\n") 42)))
> (define child-evt (cache-evt parent-evt))
> (sync child-evt) parent producing 42
42
> (sync child-evt) 42
procedure
(trigger-evt? v) → boolean?
v : any/c
procedure
(make-trigger-evt) → evt?
> (define t-e (make-trigger-evt))
> (sync/timeout 0 t-e) #f
procedure
evt : trigger-evt? v : any/c
> (trigger! t-e 13 42)
> (sync/timeout 0 t-e)
13
42
procedure
evt : trigger-evt?
> (cancel! t-e)
> (sync/timeout 0 t-e) #f
procedure
(epoch-evt? v) → boolean?
v : any/c
procedure
(make-epoch-evt) → evt?
> (define ee (make-epoch-evt))
procedure
(epoch-evt-advance! evt v ...) → void?
evt : epoch-evt? v : any/c
> (thread (λ () (sleep 1) (epoch-evt-advance! ee 'result))) #<thread>
> (sync ee) 'result
9 Advanced Locking
Advanced locking tools, such as read-write locks and lock tables.
(require misc1/locking) | package: misc1 |
procedure
(make-rwlock [wlock]) → rwlock?
wlock : semaphore? = (make-semaphore 1)
> (define lock (make-rwlock))
> (rwlock? lock) #t
syntax
(with-read-lock lock body ...)
> (with-read-lock lock 'protected-from-writes) 'protected-from-writes
syntax
(with-write-lock lock body ...)
> (with-write-lock lock 'exclusive-access) 'exclusive-access
procedure
(call-with-read-lock lock proc) → any
lock : rwlock? proc : (-> any)
procedure
(call-with-write-lock lock proc) → any
lock : rwlock? proc : (-> any)