value-evt
(require value-evt) | package: value-evt |
Wraps an arbitrary value into a synchronizable event.
Syncing something that is already an event works as usual.
Syncing on a procedure returns the procedure’s result unless you disable this behavior via the #:eval-proc? keyword. (If evaluated, the procedure is called with no arguments.)
Syncing on a list recursively syncs the elements of the list unless you disable this behavior via the #:recurse-lists? keyword.
In all other cases, the synchronization result is the original value.
1 Synopsis
; value-evts are both evt? and value-evt?. They sync to their argument > (define e (value-evt 9)) > e #<value-evt>
> (evt? e) #t
> (value-evt? e) #t
> (sync e) 9
; ; By default, syncing on a procedure syncs to the return value > (define proc (lambda () (+ 2 2))) > (sync (value-evt proc)) 4
; You can instead get the procedure itself back > (sync (value-evt proc #:eval-proc? #f)) #<procedure:proc>
; It's not a problem to specify #:eval-proc? on something that isn't a procedure > (sync (value-evt "eval-proc? keyword is ignored for non-proc" #:eval-proc? #f)) "eval-proc? keyword is ignored for non-proc"
; ; eventify always returns an evt ; Things that are evts are unchanged > (define ch (make-channel)) > (evt? ch) #t
> (eq? ch (eventify ch)) #t
; Things that are not evts become value-evts > (evt? 'bob) #f
> (evt? (eventify 'bob)) #t
; ; by default, value-evts containing a list sync recursively
> (let ([result-ch (make-channel)] [arg-ch1 (make-channel)] [arg-ch2 (make-channel)]) (void (thread (λ () (channel-put result-ch (sync (value-evt (list arg-ch1 arg-ch2))))))) (channel-put arg-ch1 'arg1-ch-ok) (channel-put arg-ch2 'arg2-ch-ok) (sync result-ch)) '(arg1-ch-ok arg2-ch-ok)
; ; You can ask for it to return the original list
> (let ([arg-ch1 (make-channel)] [arg-ch2 (make-channel)]) (sync (value-evt (list arg-ch1 arg-ch2) #:recurse-lists? #f))) '(#<channel> #<channel>)
; ; all-evt is the same as value-evt but takes a rest argument ; so you don't have to supply your own list
> (let ([result-ch (make-channel)] [arg-ch1 (make-channel)] [arg-ch2 (make-channel)]) (define e (all-evt arg-ch1 arg-ch2)) (printf "all-evt returns: ~v" e) (void (thread (λ () (channel-put result-ch (sync e))))) (channel-put arg-ch1 'arg1-ch-ok) (channel-put arg-ch2 'arg2-ch-ok) (sync result-ch)) all-evt returns: #<value-evt>
'(arg1-ch-ok arg2-ch-ok)
2 API
procedure
(value-evt v [ #:eval-proc? eval-proc? #:recurse-lists? recurse-lists?]) → value-evt? v : any/c eval-proc? : boolean? = #t recurse-lists? : boolean? = #t
If the value is a procedure and eval-proc? is #t (the default) then the procedure will be called with no arguments and the synchronization result of the value-evt will be the return value of the procedure.
If the value is a list and recurse-lists? is #t (the default) then each element of the list will have (compose1 sync eventify) called on it and the synchronization event of the original event will be a list containing the synchronization results of each of the list items. This process is recursive.
This provides a convenient way to run an arbitrary function and wait for it to complete without having to do polling, apply strictures to your interface (if the function is being passed in), or otherwise contort the code. If you want to actually return the lambda then you may use #:eval-proc? #f. Similarly, #:recurse-lists? makes it easy to handle the case where you want to wait for multiple events to complete before proceeding. A typical example would be waiting for a network connection to a server and simultaneously waiting for configuration files to be read and setup to be performed.
procedure
(value-evt? v) → boolean?
v : any/c
procedure
(eventify v [ #:eval-proc? eval-proc? #:recurse-lists? recurse-lists?]) → evt? v : any/c eval-proc? : boolean? = #t recurse-lists? : boolean? = #t
procedure
(all-evt [ #:eval-proc? eval-proc? #:recurse-lists? recurse-lists?] arg ...) → value-evt? eval-proc? : boolean? = #t recurse-lists? : boolean? = #t arg : any/c