I was hoping someone can explain why the compile
function is not working as I would expect.
First question:
* (compile 'square (lambda (x) (* x x)))
SQUARE
NIL
NIL
But then:
* (square 3)
; in: SQUARE 3
; (SQUARE 3)
;
; caught STYLE-WARNING:
; undefined function: COMMON-LISP-USER::SQUARE
;
; compilation unit finished
; Undefined function:
; SQUARE
; caught 1 STYLE-WARNING condition
* (describe 'square)
COMMON-LISP-USER::SQUARE
[symbol]
SQUARE names an undefined function
Assumed type: FUNCTION
What does this mean?
Second question, starting over:
* (defun square (x) (* x x x)) ;faulty definition
SQUARE
* (compile 'square (lambda (x) (* x x))) ;attempted correction
SQUARE
NIL
NIL
* (square 3)
27
Here the old definition is still in place. However, the hyperspec says about compile
: "If a non-nil name is given, then the resulting compiled function replaces the existing function definition of name and the name is returned as the primary value;".
(ps: my goal is to define (or update) a function programmatically, but have it be recognized by the sbcl static profiler--otherwise, it is ignored. An alternative is to use the statistical profiler, but it doesn't seem to work in windows-64.)
Edit 5/26/24 & 5/27/24: Thanks for the enlightening discussions. I tend to agree with ignis volens that sbcl's implementation of compile
could be improved. Maybe someone with a deeper understanding of the details could discuss this with the maintainers. Re my initial objective of building lambda expressions that are recognized by the sbcl static profiler, I have a simplified example that for better or worse seems to work and readily integrates into existing structures, so I'll use this unless there's a downside:
* (defmacro init-fns (name1 name2)
`(progn (defun ,name1 ()) ;define dummy fns at top-level
(defun ,name2 ())))
INIT-FNS
* (init-fns square cube)
CUBE
* (defun build-fns ()
(setf (symbol-function 'square)
(compile nil '(lambda (x) (* x x))))
(setf (symbol-function 'cube)
(compile nil '(lambda (x) (* x x x)))))
BUILD-FNS
* (build-fns)
#<FUNCTION (LAMBDA (X)) {2479F75B}>
* (square 3)
9
* (cube 3)
27
Compiling an already compiled function in SBCL
The problem is very subtle:
(compile 'square (lambda (x) (* x x)))
COMPILE
is a function. Now look at (lambda (x) (* x x))
. What is it evaluated?
> (compiled-function-p (lambda (x) (* x x)))
T
It is a compiled function!
In SBCL all functions are by default compiled.
Now we call COMPILE
on an already compiled function.
What's going on?
COMPILE
with a name and a compiled functionOne can argue that it nevertheless should set the function. Best to discuss that with the maintainers
Compiling source code
This works:
CL-USER> (compile 'square '(lambda (x) (* x x)))
SQUARE
NIL
NIL
CL-USER> #'square
#<FUNCTION SQUARE>
It works because '(lambda (x) (* x x))
evaluates to a list, which is a valid LAMBDA
macro form. The compiler will compile this source successfully and then set the symbol function of SQUARE
to the resulting compiled function.
Compare with another CL implementation, here LispWorks
Compare with LispWorks, which does not compile functions by default.
CL-USER 134 > (let ((f (compile nil '(lambda (x) (* x x)))))
(compile 'square f))
;;;*** Warning in SQUARE: The definition supplied for SQUARE is already compiled.
SQUARE
((SQUARE #<CONDITIONS::SIMPLE-STYLE-WARNING 80101F2C9B>))
NIL
CL-USER 135 > (symbol-function 'square)
#<Function 14 8020000CB9>
LispWorks warns that the function is already compiled and sets the symbol function of SQUARE
anyway.