This is the mail archive of the guile@cygnus.com mailing list for the guile project.
| Index Nav: | [Date Index] [Subject Index] [Author Index] [Thread Index] | |
|---|---|---|
| Message Nav: | [Date Prev] [Date Next] | [Thread Prev] [Thread Next] |
A while back, I was trying to learn defmacros, so I tried to write
a version of 'fluid-let'. It turned out that I was missing some
important concepts, but finally I produced something that sort of
worked. The person who helped me on the list challenged me to then
go produce a version of fluid-let that works for guile's fluid variables,
so that it would be useful in a threaded environment.
Finally, I've had some use for such a beast, and since I didn't find
one anywhere in the guile source, I decided to whip up a version. It
was pretty easy for me to do, but that just probably means that I've
got some obvious bugs in there. Can those who know macros and fluid
semantics take a look?
Something like this (assuming it works right) should be included in
the guile distribution.
-russ
#!/opt/guile/bin/guile -s
!#
(define-module (gs fluid-let))
;;; end-header
;;; Copyright (C) 1999 Russ McManus
;;;
;;; This program is free software; you can redistribute it and/or modify
;;; it under the terms of the GNU General Public License as published by
;;; the Free Software Foundation; either version 2 of the License, or
;;; (at your option) any later version.
;;;
;;; This program 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 General Public License for more details.
;;;
;;; You should have received a copy of the GNU General Public License
;;; along with this program; if not, write to the Free Software
;;; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
;;;
;;; Documentation:
;;;
;;; We require that there is a fluid-variable called
;;; *fluid-let-bindings*, which will be an association list that
;;; associates the name of bound fluid variables with their previous
;;; values. At the beginning of a 'fluid-let', we push some pairs
;;; onto this alist, and at the end, we pop them off. Voila!
;;;
;;; To avoid searching, we assume that items are put onto the bind
;;; stack in order, and that 'fluid-let' will pop them off in order. We
;;; continue to keep both the names of the vars along with the values,
;;; even though this is not strictly necessary, as a help to debugging
;;; and possibly future reflection.
;;;
;;; One can only bind fluid variables with this version fluid-let; it
;;; won't work for regular variables. If you don't care about
;;; threads, you can get a version of fluid-let that works for normal
;;; variables out of slib.
; (define a (let ((val (make-fluid)))
; (fluid-set! val 1)
; val))
; (define b (let ((val (make-fluid)))
; (fluid-set! val 2)
; val))
; (list (fluid-ref a) (fluid-ref b))
; (fluid-let ((a 2)
; (b 3))
; (list (fluid-ref a) (fluid-ref b)))
; (list (fluid-ref a) (fluid-ref b))
(define *fluid-let-bindings*
(let ((val (make-fluid)))
(fluid-set! val '())
val))
(defmacro fluid-let (clauses . body)
(let ((%make-binding (gensym))
(%binding-value (gensym))
(%add-binding (gensym))
(%pop-binding (gensym)))
`(let ((,%make-binding (lambda (key value) (cons key value)))
(,%binding-value (lambda (bind) (cdr bind)))
(,%add-binding
(lambda (bind)
(fluid-set! *fluid-let-bindings* (cons bind (fluid-ref *fluid-let-bindings*)))))
(,%pop-binding
(lambda ()
(let ((bind (car (fluid-ref *fluid-let-bindings*))))
(fluid-set! *fluid-let-bindings* (cdr (fluid-ref *fluid-let-bindings*)))
bind))))
(dynamic-wind
(lambda ()
,@(map (lambda (clause)
`(begin
(,%add-binding (,%make-binding ',(car clause) (fluid-ref ,(car clause))))
(fluid-set! ,(car clause) ,(cadr clause))))
clauses))
(lambda ()
,@body)
(lambda ()
,@(map (lambda (clause)
`(fluid-set! ,(car clause) (,%binding-value (,%pop-binding))))
(reverse clauses)))))))
(export *fluid-let-bindings*)
(export fluid-let)
--
They don't make nostalgia like they used to.