;;; Copyright (C) 2025 Free Software Foundation, Inc.
;;;
;;; This library is free software: you can redistribute it and/or modify
;;; it under the terms of the GNU Lesser General Public License as
;;; published by the Free Software Foundation, either version 3 of the
;;; License, or (at your option) any later version.
;;;
;;; This library is distributed in the hope that it will be useful, but
;;; WITHOUT ANY WARRANTY; without even the implied warranty of
;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;;; Lesser General Public License for more details.
;;;
;;; You should have received a copy of the GNU Lesser General Public
;;; License along with this program. If not, see
;;; .
;;; Commentary:
;;;
;;;
;;; Code:
(define-module (ice-9 promises)
#:use-module (srfi srfi-9)
#:use-module (ice-9 threads)
;; FIXME: #:export instead of #:replace when deprecated code removed
#:replace (make-promise
force
delay
promise?))
(define-record-type
(%make-promise computed? data lock)
%promise?
(computed? promise-computed? set-promise-computed?!)
(data promise-data set-promise-data!)
(lock promise-lock))
(define (make-promise thunk)
"Create a new promise object.
@code{make-promise} is a procedural form of @code{delay}.
These two expressions are equivalent:
@lisp
(delay @var{exp})
(make-promise (lambda () @var{exp}))
@end lisp"
(%make-promise #f thunk (make-recursive-mutex)))
(define-syntax-rule (delay exp)
(make-promise (lambda () exp)))
(define (force promise)
"If @var{promise} has not been computed yet, compute and return
@var{promise}, otherwise just return the previously computed value."
(with-mutex (promise-lock promise)
(if (promise-computed? promise)
(promise-data promise)
(let* ((thunk (promise-data promise))
(ans (thunk)))
(if (promise-computed? promise)
(promise-data promise)
(begin
(set-promise-computed?! promise #t)
(set-promise-data! promise ans)
ans))))))
(define (promise? x)
"Return true if @var{obj} is a promise, i.e. a delayed
computation (@pxref{Delayed evaluation,,,r5rs.info,The Revised^5 Report
on Scheme})."
(%promise? x))