[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: strange 1+/1- bug?
Richard Shepherd writes:
>
> (defun 1+ (x) (+ x 1))
> -> ** - Continuable Error
> Redefining the COMMON LISP function 1+
> If you continue (by typing 'continue'): The old definition will be
> lost
> 1. Break> continue
> -> 1+
> (1+ 3)
> -> 4
> (compile '1+)
> -> 1+
> (1+ 3)
> -> *****hangs***** i.e. never returns, infinite loop, etc.
Of course. The CLISP compiler recognizes that (+ x 1) is equivalent to
(1+ x) and thus generates a tail-recursive call, just as if you had written
(defun 1+ (x) (1+ x)).
> (defun 1+ (x) (+ x 1))
** - Continuable Error
Redefining the COMMON LISP function 1+
If you continue (by typing 'continue'): The old definition will be lost
1. Break> continue
1+
> (disassemble #'1+) ;; disassemble without installing the compiled definition
Disassembly of function 1+
1 required arguments
0 optional arguments
No rest parameter
No keyword parameters
0 L0
0 (LOAD&PUSH 1)
1 (JMPTAIL 1 3 L0)
#<COMPILED-CLOSURE 1+>
> Is this a bug that is fixed in later versions?
No, this isn't a bug. You are not allowed to modify built-in Common Lisp
functions (see CLtL2 or dpANS), and that's what the warning was about.
> What's so special about the 1 in addition?
The compiler optimizes (+ x 1), but not (+ x 2).
> PS: this all came about 'cos I was simulating operator overloading in
> CLOS and decided to redefine 1+ and 1- just to be on the safe side (I
> know it probably throws away a lot of efficiency, but doesn't CLOS
> anyway?)
Using CLOS for arithmetic operations provides a great flexibility.
But redefining 1+ is a no-no. That's what Common Lisp packages are for.
Here is an example of code, written by Michael Stoll, so you get the
idea.
=========================== part of domain.lsp ===========================
(provide :domain)
(defpackage "DOMAIN"
(:use "LISP" "CLOS")
(:shadow "NUMBERP" "=" "ZEROP" "INTEGERP" "EXQUO" "EXPT"
"NUMERATOR" "DENOMINATOR" "+" "-" "*" "/" "GCD" "LCM")
(:export "DIVIDE" "NORMALIZE" "DOMAINIFY"))
(in-package :domain)
(eval-when (load eval compile) (pushnew ':DOMAIN *features*))
(eval-when (load eval)
(defmacro domainify ()
`(progn
(defpackage ,(package-name *package*)
(:shadowing-import-from "DOMAIN"
"NUMBERP" "=" "ZEROP" "INTEGERP" "EXQUO" "EXPT"
"NUMERATOR" "DENOMINATOR" "+" "-" "*" "/" "GCD" "LCM"
"DIVIDE" "NORMALIZE")
(:use ,@(mapcar #'package-name (package-use-list *package*)))))))
;; At the beginning of every program which uses the domain package
;; you write (after the in-package form)
;; #+DOMAIN (domain:domainify)
============================================================================
Bruno Haible email: <haible@ilog.fr>
Software Engineer phone: +33-1-49083585