From 6e8c0b6088a8a98367d2222cad3d296542a01657 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Wed, 10 Jul 2019 18:53:23 -0400 Subject: [PATCH] Functional build-out of delay --- libs/cyclone/delay-promise.scm | 44 ++++++++++++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/libs/cyclone/delay-promise.scm b/libs/cyclone/delay-promise.scm index 0dcb8ea3..cd5d956c 100644 --- a/libs/cyclone/delay-promise.scm +++ b/libs/cyclone/delay-promise.scm @@ -1,3 +1,43 @@ -TODO: support for concurrent delay and promise as implemented by Clojure +;; TODO: support for concurrent delay and promise as implemented by Clojure +;; See: https://purelyfunctional.tv/guide/clojure-concurrency/ -See: https://purelyfunctional.tv/guide/clojure-concurrency/ +(import (scheme write) (scheme base) (cyclone concurrent) (srfi 18)) + +(define-record-type + (%make-delay done result lock) + delay? + (done delay:done delay:set-done!) + (value delay:value delay:set-value!) ;; Either thunk or result + (lock delay:lock delay:set-lock!)) + +(define (make-delay thunk) + (%make-delay #f thunk (make-mutex))) + +(define (delay-deref d) + (when (not (delay? d)) + (error "Expected future but received" d)) + (mutex-lock! (delay:lock d)) + (cond + ((delay:done d) + (delay:value d)) + (else + (delay:set-value! d + (make-shared ((delay:value d)))) ;; Exec thunk and store result + (delay:set-done! d #t))) + (mutex-unlock! (delay:lock d)) +) + +(define-syntax shared-delay + (er-macro-transformer + (lambda (expr rename compare) + `(make-delay (lambda () ,(cadr expr)))))) + + +(define (test) + (write '(testing)) (newline) + 'done) + +(define d (shared-delay (test))) +(write (delay-deref d))(newline) +(write (delay-deref d))(newline) +(write (delay-deref d))(newline)