From: Tamas
Subject: how to find the definition of cmucl's once-only?
Date: 
Message-ID: <1176318792.931157.282100@l77g2000hsb.googlegroups.com>
Hi,

I read about once-only in Seibel's book.  I wanted to use it in my
programs, and when trying that, I found that cmucl already includes
this macro.  However, it seems that it has a slightly different
syntax, and I can't figure out what it is.  Could somebody please tell
me how to do that?  I tried looking at the CMUCL manual, but couldn't
find it, C-c C-k in Emacs displays #<Byte function (:MACRO ONCE-ONLY)
{280B6009}> is function which didn't help much.  Maybe I am just
looking in the wrong places...

Thanks,

Tamas

From: GP lisper
Subject: Re: how to find the definition of cmucl's once-only?
Date: 
Message-ID: <slrnf1qlg6.v2t.spambait@phoenix.clouddancer.com>
On 11 Apr 2007 12:13:12 -0700, <······@gmail.com> wrote:
> Hi,
>
> I read about once-only in Seibel's book.  I wanted to use it in my
> programs, and when trying that, I found that cmucl already includes
> this macro.  However, it seems that it has a slightly different
> syntax, and I can't figure out what it is.  Could somebody please tell
> me how to do that? 

Using Lars trick, at the slime REPL on cmucl
(once-only x y) and then I used the GUI drop-down for Edit Def...

you find it in extensions.lisp

;;;; The Once-Only macro:

;;; Once-Only  --  Interface
;;;
;;;    Once-Only is a utility useful in writing source transforms and macros.
;;; It provides an easy way to wrap a let around some code to ensure that some
;;; forms are only evaluated once.
;;;
(defmacro once-only (specs &body body)
  "Once-Only ({(Var Value-Expression)}*) Form*
  Create a Let* which evaluates each Value-Expression, binding a temporary
  variable to the result, and wrapping the Let* around the result of the
  evaluation of Body.  Within the body, each Var is bound to the corresponding
  temporary variable."
  (iterate frob
	   ((specs specs)
	    (body body))
    (if (null specs)
	`(progn ,@body)
	(let ((spec (first specs)))
	  (when (/= (length spec) 2)
	    (error "Malformed Once-Only binding spec: ~S." spec))
	  (let ((name (first spec))
		(exp-temp (gensym)))
	    `(let ((,exp-temp ,(second spec))
		   (,name (gensym "OO-")))
	       `(let ((,,name ,,exp-temp))
		  ,,(frob (rest specs) body))))))))



-- 
There are no average Common Lisp programmers
Reply-To: email is ignored.

-- 
Posted via a free Usenet account from http://www.teranews.com
From: Lars Rune Nøstdal
Subject: Re: how to find the definition of cmucl's once-only?
Date: 
Message-ID: <461d4628$0$29079$c83e3ef6@nn1-read.tele2.net>
On Wed, 11 Apr 2007 12:13:12 -0700, Tamas wrote:

> Hi,
> 
> I read about once-only in Seibel's book.  I wanted to use it in my
> programs, and when trying that, I found that cmucl already includes
> this macro.  However, it seems that it has a slightly different
> syntax, and I can't figure out what it is.  Could somebody please tell
> me how to do that?  I tried looking at the CMUCL manual, but couldn't
> find it, C-c C-k in Emacs displays #<Byte function (:MACRO ONCE-ONLY)
> {280B6009}> is function which didn't help much.  Maybe I am just
> looking in the wrong places...
> 
> Thanks,
> 
> Tamas

I'm using SBCL here, but CMUCLs version of once-only might be similar. I
type in sb-int:once-only at the REPL and press M-. 

That will make Slime automatically navigate to a buffer with the file
with the definition of the once-only macro in it (early-extensions.lisp in
SBCL).

Pressing M-, will navigate back to the REPL. M-. and M-, can be used
multiple times by the way. It "remembers history":
  http://common-lisp.net/project/slime/doc/html/Finding-definitions.html

Here is how once-only is defined in SBCL:

;;;; ONCE-ONLY
;;;;
;;;; "The macro ONCE-ONLY has been around for a long time on various
;;;; systems [..] if you can understand how to write and when to use
;;;; ONCE-ONLY, then you truly understand macro." -- Peter Norvig,
;;;; _Paradigms of Artificial Intelligence Programming: Case Studies
;;;; in Common Lisp_, p. 853

;;; ONCE-ONLY is a utility useful in writing source transforms and
;;; macros. It provides a concise way to wrap a LET around some code
;;; to ensure that some forms are only evaluated once.
;;;
;;; Create a LET* which evaluates each value expression, binding a
;;; temporary variable to the result, and wrapping the LET* around the
;;; result of the evaluation of BODY. Within the body, each VAR is
;;; bound to the corresponding temporary variable.
(defmacro once-only (specs &body body)
  (named-let frob ((specs specs)
                   (body body))
    (if (null specs)
        `(progn ,@body)
        (let ((spec (first specs)))
          ;; FIXME: should just be DESTRUCTURING-BIND of SPEC
          (unless (proper-list-of-length-p spec 2)
            (error "malformed ONCE-ONLY binding spec: ~S" spec))
          (let* ((name (first spec))
                 (exp-temp (gensym (symbol-name name))))
            `(let ((,exp-temp ,(second spec))
                   (,name (gensym "ONCE-ONLY-")))
               `(let ((,,name ,,exp-temp))
                  ,,(frob (rest specs) body))))))))


I have PAIP here. Here is how once-only is defined in PAIP:


(defmacro once-only (variables &rest body)
  "Returns the code built by BODY.  If any of VARIABLES
  might have side effects, they are evaluated once and stored
  in temporary variables that are then passed to BODY."
  (assert (every #'symbolp variables))
  (let ((temps nil))
    (dotimes (i (length variables)) (push (gensym) temps))
    `(if (every #'side-effect-free? (list .,variables))
         (progn .,body)
         (list 'let
               ,`(list ,@(mapcar (lambda (tmp var)
                                   `(list ',tmp ,var))
                                 temps variables))
               (let ,(mapcar (lambda (var tmp) `(,var ',tmp))
                             variables temps)
                 .,body))))) 

(defun side-effect-free? (exp)
  "Is exp a constant, variable, or function,
  or of the form (THE type x) where x is side-effect-free?"
  (or (atom exp) (constantp exp)
      (starts-with exp 'function)
      (and (starts-with exp 'the)
           (side-effect-free? (third exp)))))


..it's also available here: http://norvig.com/paip/auxfns.lisp

-- 
Lars Rune Nøstdal
http://nostdal.org/
From: Lars Rune Nøstdal
Subject: Re: how to find the definition of cmucl's once-only?
Date: 
Message-ID: <461d4858$0$29079$c83e3ef6@nn1-read.tele2.net>
On Wed, 11 Apr 2007 20:33:44 +0000, Lars Rune Nøstdal wrote:

> I type in sb-int:once-only

..and I figured out that once-only was in the sb-int package by using
apropos:

> (apropos 'once-only)
sb-int:once-only (fbound)


Sometimes using describe will give more info about stuff:

> cl-user> (describe 'sb-int:once-only)
sb-int:once-only is an external symbol in #<package "SB-INT">.
Macro-function: #<FUNCTION (macro-function sb-int:once-only) {95E2C9D}>
Its associated name (as in function-lambda-expression) is
  (macro-function sb-int:once-only).
The macro's arguments are:  (specs &body body)
On Sun, Apr 1, 2007 11:22:22 PM [-1] it was compiled from:
SYS:SRC;CODE;EARLY-EXTENSIONS.LISP
  Created: Sunday, April 1, 2007 11:19:50 PM [-1]

..not too much info this time though. :) That's where M-. and M-, is handy.

-- 
Lars Rune Nøstdal
http://nostdal.org/