This is the mail archive of the 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]

Dynamic binding: lisp-ref and lisp-set!


(This message is about Guile Emacs, but is also something about Guile
in general.)

I'm thinking of not using procedure-with-setter to refer to Lisp
variables.  The binding to Lisp variables is dynamic, and I'm not sure
about the Guile's dynamic features.  One Guile's (kind of) dynamic variable
is fluid, which changes the value depending on the current dynamic root.
A fluid uses fluid-ref and fluid-set! to access the value.  I guess
we'd better use the same way for Lisp variables.  This is a GOOPS version
of lisp-ref/set!:

  (define-class <lisp-variable> ()
    (sym #:accessor sym #:init-keyword #:symbol)
    (var #:allocation #:virtual
         #:slot-ref (lambda (i) (%lisp-eval (sym i)))
         #:slot-set! (lambda (i v)
                       (%lisp-eval `(setq ,(sym i) ',v))
         #:getter lisp-ref
         #:setter lisp-set!))

  (define-method (write (obj <lisp-variable>) port)
    (display "#<lisp-variable " port)
    (display (sym obj) port)
    (display ">" port))

  (define name (make <lisp-variable> #:symbol 'user-full-name))

  => #<lisp-variable user-full-name>
  (lisp-ref name)
  => #<foreign-object <emacs-string> 40480ce0>
  (%lisp->scheme (lisp-ref name))
  => "Keisuke Nishida"

The new Emacs Scheme code might look like this:

  (insert (lisp-ref user-full-name))

We could do the same thing more naturally by defining a procedure so
as to accept <lisp-variable>:

  (define-method (insert (obj <lisp-variable>))
    (insert (lisp-ref obj)))

  (insert user-full-name)

However, this requires us to define similar methods for all procedures,
which is practically impossible.  In order to write the latter natural
expression (in the sense of Emacs Lisp), I guess we have to modify the
Guile's evaluator so that it handles special objects like this:

  (define foo (make-dynamic-object
               (lambda () (make-variable #f))
               (lambda (variable) (variable-ref variable))
               (lambda (variable value) (variable-set! variable value))))
  foo => #f
  (set! foo "Hello")
  foo => "Hello"

Using this object, a fluid can be written as

  (define foo (make-dynamic-object
               (lambda () (make-fluid))
               (lambda (fluid) (fluid-ref fluid))
               (lambda (fluid value) (fluid-set! fluid value))))
  foo => #f
  (set! foo "Hello")
  foo => "Hello"

and our Lisp reference can be written as

  (define foo (make-dynamic-object
               (lambda () 'user-full-name)
               (lambda (symbol) (%lisp-eval symbol))
               (lambda (symbol value) (%lisp-eval `(setq ,symbol ',value)))))
  foo => #<foreign-object <emacs-string> 40480ce0>
  (set! foo "Hello")
  foo => #<foreign-object <emacs-string> 40480ce8>

I asked about the Guile's new top-level environment if I could use it
to do my job, but the answer was no.  The environment also seems to be
(kind of) static; that is, environment-ref/set! is called only once at
evaluation time (not at run time).

I believe make-dynamic-object can be implemented, but I'm not sure
whether it is a good thing or not.  What do people think?

-- Kei

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]