Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Common lisp: Redefine an existing function within a scope?

Tags:

common-lisp

In Common Lisp, is it possible to redefine an already defined function within a certain scope? For example, given a function A that calls a function B. Can I temporarily redefine B during a call to A?

I'm looking for something along the lines of a let block, but that can redefine functions.

like image 836
Erik Öjebo Avatar asked Jun 19 '10 07:06

Erik Öjebo


People also ask

How do you define a function in a Common Lisp?

Use defun to define your own functions in LISP. Defun requires you to provide three things. The first is the name of the function, the second is a list of parameters for the function, and the third is the body of the function -- i.e. LISP instructions that tell the interpreter what to do when the function is called.

What is the difference between extent and scope?

Scope refers to the spatial or textual region of the program within which references may occur. Extent refers to the interval of time during which references may occur.

What does Setf do in Lisp?

setf is actually a macro that examines an access form and produces a call to the corresponding update function. Given the existence of setf in Common Lisp, it is not necessary to have setq, rplaca, and set; they are redundant. They are retained in Common Lisp because of their historical importance in Lisp.

How do you stop a Lisp from functioning?

To terminate the Lisp system, use the command ":exit" or call the function "(exit)."


3 Answers

Within a given lexical scope, yes. Use FLET or LABELS. Any function defined with FLET will be unable to call functions defined in the same lexical scope, if you want that (for, say, self-recursive of a group of mutually recursive functions), you will need to use LABELS.

Note that both FLET and LABELS only establish lexical shadowing, should not be used to shadow functions from the COMMON-LISP package and will not dynamically change what function is called from outside the lexical scope the form establishes.

like image 146
Vatine Avatar answered Oct 03 '22 16:10

Vatine


Local functions can be introduced with FLET and LABELS.

like image 33
Rainer Joswig Avatar answered Oct 03 '22 15:10

Rainer Joswig


If you want to redefine/shadow an existing function using dynamic scope, this is a macro I've been using for a while.

(defmacro! with-shadow ((fname fun) &body body)
  "Shadow the function named fname with fun
   Any call to fname within body will use fun, instead of the default function for fname.
   This macro is intentionally unhygienic:
   fun-orig is the anaphor, and can be used in body to access the shadowed function"
  `(let ((fun-orig))
     (cond ((fboundp ',fname)
            (setf fun-orig (symbol-function ',fname))
            (setf (symbol-function ',fname) ,fun)
            (unwind-protect (progn ,@body)
              (setf (symbol-function ',fname) fun-orig)))
           (t
            (setf (symbol-function ',fname) ,fun)
            (unwind-protect (progn ,@body)
              (fmakunbound ',fname))))))

Usage:

Clozure Common Lisp Version 1.9-r15759  (DarwinX8664)  Port: 4005  Pid: 4728
; SWANK 2012-03-06
CL-USER>  
(defun print-using-another-fname (x)
  (print x))
PRINT-USING-ANOTHER-FNAME

CL-USER> 
(let ((*warn-if-redefine-kernel* nil))
  (with-shadow (print (lambda (x)
                        (funcall fun-orig (+ x 5))))
    (print-using-another-fname 10)))

15 
15
CL-USER>                
(print 10)

10 
10
CL-USER> 

Note that it relies on Doug Hoyte's defmacro! macro, available in Let Over Lambda.

Also as written, it's anaphoric (fun-orig is available within the body). If you want it completely hygienic, just change the fun-orig's to ,g!fun-orig's.

I most often redefine functions when writing unit tests. Mocking functions within the scope of a particular unit test is helpful, and sometimes that needs to be done with dynamic (not lexical) scope.

like image 22
Clayton Stanley Avatar answered Oct 03 '22 15:10

Clayton Stanley