I'm writing some code in SBCL, and the ordering of my functions keeps causing warnings of the following type to appear when I load files into the REPL:
;caught STYLE-WARNING:
undefined function: FOO
Where FOO is the symbol for the function. This is purely due to how they are ordered in my file, as the function FOO is defined, just not before the part of the code that throws that warning.
Now, in Clojure, which is the Lisp I'm familiar with, I have the declare form, which lets me make forward declarations to avoid this kind of issue. Is there something similar for SBCL/Common Lisp in general?
We can use the '(declaim (ftype ...))' for that:
(declaim (ftype (function (integer list) t) ith))
(defun foo (xs)
(ith 0 xs))
(defun ith (n xs)
(nth n xs))
Both the function 'foo' and 'ith' works fine and there is not any style warning about that.
http://www.lispworks.com/documentation/HyperSpec/Body/d_ftype.htm
Here's what I found in the manual, section 4.1.1:
CL-USER> (defun foo (x) (bar x))
; in: DEFUN FOO
; (BAR X)
;
; caught STYLE-WARNING:
; undefined function: BAR
;
; compilation unit finished
; Undefined function:
; BAR
; caught 1 STYLE-WARNING condition
FOO
CL-USER> (declaim (sb-ext:muffle-conditions style-warning))
; No value
CL-USER> (defun baz (y) (quux y))
BAZ
So you can at least silence the style warnings.
I also thought about how SBCL is handling the evaluation step in the REPL: it compiles the code. So I restarted the inferior lisp process and ran "compile region" on the following two lines:
(defun foo (x) (bar x))
(defun bar (y) (baz y))
and SBCL only complained about baz, but not about bar. Are you giving single functions to SBCL or larger chunks?
Related
I'm trying to pass a symbol of a condition of a function to a macro, and see the result:
(defmacro macro-test-1 (form condition)
`(handler-case (funcall ,form)
(,condition (c)
(declare (ignore c))
(format t "~a" 'why?))))
(macro-test-1 #'(lambda () (error 'simple-type-error)) division-by-zero)
;; OK, I get the simple-type-error as expected.
(defun test-1 (condition)
(macro-test-1 #'(lambda () (error 'simple-type-error)) condition))
; in: DEFUN TEST-1
; (SB-INT:NAMED-LAMBDA TEST-1
; (CONDITION)
; (BLOCK TEST-1
; (MACRO-TEST-1 #'(LAMBDA () (ERROR 'SIMPLE-TYPE-ERROR)) CONDITION)))
;
; caught STYLE-WARNING:
; The variable CONDITION is defined but never used.
;
; compilation unit finished
; caught 1 STYLE-WARNING condition
TEST-1
;; what happened?
(test-1 'division-by-zero)
WHY?
NIL
;; what happened?
I'm pretty confused by what's going on, I've been trying to figure it out for a long time, I hope I'm missing something silly.
up 1
It is as I imagined, silly error, now I realized what I was trying to do, the macro will be expanded at compile time, and the argument I pass to the function at runtime, so the macro will not receive the condition argument correctly. So I see two possibilities of solving this, turning macro-test-1 into a function or turning test-1 into a macro.
Actually I tested here, changing to function still not working:
CL-USER> (defun macro-test-1 (form condition)
(handler-case (funcall form)
(condition (c)
(declare (ignore c))
(format t "~a" 'why?))))
; in: DEFUN MACRO-TEST-1
; (SB-INT:NAMED-LAMBDA MACRO-TEST-1
; (FORM CONDITION)
; (BLOCK MACRO-TEST-1
; (HANDLER-CASE (FUNCALL FORM)
; (CONDITION (C) (DECLARE #) (FORMAT T "~a" 'WHY?)))))
;
; caught STYLE-WARNING:
; The variable CONDITION is defined but never used.
;
; compilation unit finished
; caught 1 STYLE-WARNING condition
WARNING: redefining COMMON-LISP-USER::MACRO-TEST-1 in DEFUN
CL-USER> (macro-test-1 #'(lambda () (error 'simple-type-error)) 'division-by-zero)
WHY?
NIL
However when you redefine macro-test-1 as a macro, and redefine test-1 as a macro:
CL-USER> (defmacro test-1 (condition)
`(macro-test-1 #'(lambda () (error 'simple-type-error)) ,condition))
TEST-1
CL-USER> (test-1 division-by-zero)
; Evaluation aborted on #<SIMPLE-TYPE-ERROR {1001BB8FF3}>.
I'm still not sure why the function does not work, the evaluation rule is not to evaluate all arguments and then pass to the body of the function the evaluated arguments? Because it does not work?
up 2
I understand that the handler-case does not work because you need to know the errors at compile time, and passing condition as a runtime function argument would not be able to know the compile-time error, so it does not work. And I stress this single reason, and not because macros occur has compile time, by a question I noted below which led me to this whole mess, and made me believe it is possible to pass condition by a function. I can do this:
(defmacro macro-test-1 (fn value)
`(funcall ,fn ,value 1))
(macro-test-1 #'= 1)
;; => T it is OK
(defun test-1 (fn value)
(macro-test-1 fn value))
(test-1 #'= 1)
;; => why it is OK?
The above code works, even though I pass the arguments to the function at runtime, why does it work? if the macro is expanded at compile time, why is it working when I call test-1? or are macros not always expanded at compile time? What am I missing here?
up 3
I decided to go deeper, and tried:
(defmacro macro-test-1 (fn value)
`(,fn ,value 1))
(macro-test-1 = 1)
;; => T it is OK
(defun test-1 (fn value)
(macro-test-1 fn value))
; in: DEFUN TEST-1
; (SB-INT:NAMED-LAMBDA TEST-1
; (FN VALUE)
; (BLOCK TEST-1 (MACRO-TEST-1 FN VALUE)))
;
; caught STYLE-WARNING:
; The variable FN is defined but never used.
; in: DEFUN TEST-1
; (MACRO-TEST-1 FN VALUE)
; ==>
; (FN VALUE 1)
;
; caught STYLE-WARNING:
; undefined function: FN
;
; compilation unit finished
; Undefined function:
; FN
; caught 2 STYLE-WARNING conditions
WARNING: redefining COMMON-LISP-USER::TEST-1 in DEFUN
TEST-1
Yes I know that if I try as shown below, it will not exit as expected:
(test-1 '= 1)
; Evaluation aborted on #<UNDEFINED-FUNCTION FN {1004575323}>. ;
But I wanted to find a way to make it work, so I tried, until I could, by resetting macro-test-1 to:
(defmacro macro-test-1 (fn value)
`(eval (,fn ,value 1)))
WARNING: redefining COMMON-LISP-USER::MACRO-TEST-1 in DEFMACRO
MACRO-TEST-1
(defun test-1 (fn value)
(macro-test-1 fn value))
WARNING: redefining COMMON-LISP-USER::TEST-1 in DEFUN
TEST-1
(test-1 '= 1)
T
Of course this would only work in handler-case or case, if I redefined its macros, which I believe should not be a good practice, nor do I need it, but I like to go where it does not, well, then, I learn erring.
Macros are code transformation. Thus the expansion can happen as early as when you evaluate a defun. eg.
(defun test-1 (condition)
(macro-test-1 #'(lambda () (error 'simple-type-error)) condition))
;; becomes this
(defun test-1 (condition)
(handler-case (funcall #'(lambda nil (error 'simple-type-error)))
(condition (c)
(declare (ignore c)) (format t "~a" 'why?)))
Now just lets say you want to have handler-case check for simple-type-error. You'll write it like this:
(handler-case expression
(simple-type-error ()
(format t "~a" 'why?)))
not
(handler-case expression
('simple-type-error ()
(format t "~a" 'why?)))
Eg. handler-case is syntax and that place is can not have a variable be evaluated to some error, but must be a type specifier and that is probably handled compile time by the system. This is the reason you get that condition is never used since your handler-case checks for a type called condition, not what you sent as the condition argument.
Making test-1 a macro actually passes division-by-zero as the symbol to macro-test-1 and the result is this:
(handler-case (funcall #'(lambda nil (error 'simple-type-error)))
(division-by-zero (c)
(declare (ignore c))
(format t "~a" 'why?)))
This also means the errors need to be known compile time since you cannot have a macro be passed values in variables. That is why it works so the second you want some user to input what error to act on you cannot do it with your solution.
EDIT
In up2 you ask why this works:
(defun test-1 (fn value)
(macro-test-1 fn value))
So we'll just find out what actually gets saved:
(macroexpand-1 '(macro-test-1 fn value))
; ==> (funcall fn value)
; ==> t
Thus your function becomes this:
(defun test-1 (fn value)
(funcall fn value))
handler-case was syntax that didn't take variables or expression at the place you wanted and thats why that didn't work, but it will of course work for all functions, including funcall, since it evaluates all it's arguments.
To show you a different example of what does not work is case:
(defun check-something (what result default-value value)
(case value
(what result)
(otherwise default-value)))
case is a macro so what actually happens. We can do macroexpand-1 on it to see:
(macroexpand-1
'(case value
(what result)
(otherwise default-value))
)
; ==> (let ((tmp value))
; (cond ((eql tmp 'what) result)
; (t default-value)))
; ==> t
The macro expects the case values to be literals and thus quotes them so that they never get evaluated. The resulting function you clearly see what is never used, just as condition wasn't:
(defun check-something (what result default-value value)
(let ((tmp value))
(cond ((eql tmp 'what) result)
(t default-value))))
Macros are to abstract on syntax. You need to be able to write the code without the macro and rather see that this is a pattern that repeats and than add an abstraction that rewrites from your simplified version to the full version. If it cannot be done to begin with it cannot be rewritten as a macro.
Same for functions. The whole reason why we have macros is to control evaluation. A good example of something that cannot be written as a fucntion is if:
(defun my-if (predicate consequence alternative)
(cond (predicate consequence)
(t alternative)))
(my-if t 'true 'false) ; ==> true
(my-if nil 'true 'false) ; ==> false
But since functions always evaluates their arguments you cannot do this:
(defun factorial (n)
(my-if (<= n 1)
1
(* n (factorial (1- n)))))
This will never halt since being a function all 3 arguments are always evalaued and (* n (factorial (1- n)))) is done even when n is negative and it will have endless recursion. Using a macro instead would replace the my-if with the resulting cond and both cond and if does not evaluate all their arguments rather than short circuits on the one that matches truthy predicate.
You may use macroexpand-1 to check if you code indeed is correct. You should be able to replace the input with the ourput. Is you use macroexpand applies the expansion until it will not expand anymore. Eg. cond will also be expanded to nested if's.
EDIT 2
From up3:
(defun test-1 (fn value)
(macro-test-1 fn value))
This is the same problem. The macro function gets fn and value as bindings and the result is:
(defun test-1 (fn value)
(fn value))
This might have worked in Scheme, but in Common Lisp symbols in operator prosition is different from other positions. Thus when CL tries to find the function fn it never look any close to the variable fn. The only way to solve this is by using funcall and then you actually don't need a macro at all:
(defun with-1 (fn value)
(funcall fn value 1))
(with-1 #'+ 10) ; ==> 11
Notice the #' prefix. That is short for (function ...) so it's really (function +). function is a special form that takes the argument symbol and gets the value from the function namespace.
With eval you can do a lot of stuff, but it comes with a price. It will not be optimized and perhaps even just interpreted and it might gove you compile time errors at runtime as well as open for security risks. A good example was a online interactive ruby that just did eval and it worked well until someone evaluated code that deleted all the system files. eval is considered harmful and even evil. In my professional career I have seen eval being used 3 times on purpose. (2 times in PHP, one in requirejs). One of those times I challenged the writer that there might be a better way to do it. Of course both handler-case and case will work with eval since the evaluated code would have the correct format, but you'll loose the lexical scoping. eg.
(let ((x 10))
(eval '(+ x 1)));
; *** EVAL: variable X has no value
You might be smart and do this:
(let ((x 10))
(eval `(+ ,x 1))) ; ==> 11
but what if it was a list or something else not self evaluating?
(let ((x '(a b)))
(eval `(cons '1 ,x)))
; *** undefined function: a
Thus eval has its chalenges as well. Keep away for other purposes than education ones.
I would like to try extending some Lisp (Scheme, Racket, Clojure, any) to run external commands as follows:
; having
(define foo ...)
(define bar ...)
; on command
(ls (foo bar) baz)
; this lisp should evaluate (foo bar) as usual, with result "foobar", then
(ls foobar baz)
; here "ls" is not defined
; instead of rising "undefined identifier" exception
; it must look for "ls" command in the directories
; in the "PATH" environment variable
; and launch the first found "ls" command
; with strings "foobar" and "baz" on input
I just want to run it anyhow, without carrying about correct conversion from lisp's data structures to strings or handling the exit code and the output of the command in stdout/stderr.
I think there is no way to extend it within normal environment (like catching the "undefined" exception all the time). The eval procedure of the interpreter itself must be changed.
Which Lisp is the best to extend it like this and how is it done? Maybe there already exists a project performing something similar?
Common Lisp has a standard error system which may be used to implement that.
In Common Lisp implementations which provide a use-value or store-value restart for errors of type undefined-function.
Example
CL-USER 69 > (flet ((call-use-value-restart (c)
(use-value (lambda (arg)
(format t "~%dummy function with arg ~a~%" arg))
c)))
(handler-bind ((undefined-function #'call-use-value-restart))
(this-function-does-not-exist "foo")))
dummy function with arg foo
NIL
In the above example the function this-function-does-not-exist does not exist. As you can see, the error is handled and another function is called instead, which then does some output.
If we call the undefined function on its own, we get an error:
CL-USER 70 > (this-function-does-not-exist "foo")
Error: Undefined operator THIS-FUNCTION-DOES-NOT-EXIST in form (THIS-FUNCTION-DOES-NOT-EXIST "foo").
1 (continue) Try invoking THIS-FUNCTION-DOES-NOT-EXIST again.
2 Return some values from the form (THIS-FUNCTION-DOES-NOT-EXIST "foo").
3 Try invoking something other than THIS-FUNCTION-DOES-NOT-EXIST with the same arguments.
4 Set the symbol-function of THIS-FUNCTION-DOES-NOT-EXIST to another function.
5 Set the macro-function of THIS-FUNCTION-DOES-NOT-EXIST to another function.
6 (abort) Return to top loop level 0.
Type :b for backtrace or :c <option number> to proceed.
Type :bug-form "<subject>" for a bug report template or :? for other options.
CL-USER 71 : 1 >
Our example basically calls the restart number 3 programmatically:
It binds a handler which calls the function call-use-value-restart when an error of type undefined-function happens.
The function call-use-value-restart then calls the use-value restart with a function it provides. Here you could provide a function which calls an external program of the name given by (cell-error-name c). The use-value restart then just calls the provided function and keeps on executing the program as usual.
Hint for a solution
Typically one would write a small top-level loop where such a handler is provided.
Another way to call the restart
In this example we use a hook to add a handler in case an error happens. Here we use the global variable *debugger-hook*. This should be a function and in our case it calls a new function when the condition c is of type undefined-function.
* (defun provide-a-function-hook (c hook)
(declare (ignore hook))
(typecase c
(undefined-function (use-value (lambda (arg)
(format t "~%dummy function with arg ~a~%" arg))
c))))
PROVIDE-A-FUNCTION-HOOK
* (setf *debugger-hook* #'provide-a-function-hook)
#<FUNCTION PROVIDE-A-FUNCTION-HOOK>
* (this-function-does-not-exist "foo")
; in: THIS-FUNCTION-DOES-NOT-EXIST "foo"
; (THIS-FUNCTION-DOES-NOT-EXIST "foo")
;
; caught STYLE-WARNING:
; undefined function: THIS-FUNCTION-DOES-NOT-EXIST
;
; compilation unit finished
; Undefined function:
; THIS-FUNCTION-DOES-NOT-EXIST
; caught 1 STYLE-WARNING condition
dummy function with arg foo
NIL
In racket you may override #%top:
#lang racket
(provide
(combine-out
(except-out (all-from-out racket) #%top)
(rename-out [shell-curry #%top])))
(require racket/system)
(define (stringify a)
(~a (if (cmd? a) (cmd-name a) a)))
(struct cmd (name proc)
#:property prop:procedure
(struct-field-index proc)
#:transparent
#:methods gen:custom-write
[(define (write-proc x port mode)
(display (string-append "#<cmd:" (stringify x) ">") port))])
(define (shell name)
(define (cmd-proxy . args)
(define cmd
(string-join (map stringify (cons name args))
" "))
(system cmd))
cmd-proxy)
(define-syntax shell-curry
(syntax-rules ()
((_ . id)
(cmd 'id (shell 'id)))))
Save this as shell.rkt and make this runner.rkt in the same directory:
#lang s-exp "shell.rkt"
(define test (list /bin/ls /usr/bin/file))
(second test) ; ==> #<cmd:/usr/bin/file>
(first test) ; ==> #<cmd:/bin/ls>
((second test) (first test))
; ==> t (prints that /bin/ls is an executable on my system)
Now from here to make it a #lang myshell or something like that is pretty easy.
This question is somewhat replated to this and this for Elisp. Basically, how is the back-quote read and evaluated? What processes are happening? And does the standard say anything about it?
Here is what I would expect, but it doesn't happen: symbol ` is a reader-macro and is translated into some kind of (BACKQUOTE ...) macro/special form (similarly to ' being translated to (QUOTE ...)). This doesn't happen, and, in fact, Common Lisp doesn't even have a BACKQUOTE macro.
What is happening (SBCL):
CL-USER> (defparameter *q* (read-from-string "`(a b ,c)"))
*Q*
CL-USER> *q*
`(A B ,C)
CL-USER> (car *q*)
SB-INT:QUASIQUOTE
CL-USER> (cdr *q*)
((A B ,C))
Something different from expected, but OK. Now, ,C is an interesting beast on its own:
CL-USER> (type-of (third (cadr *q*)))
SB-IMPL::COMMA
If there are no comma-symbols, evaluating the read expression is fine:
CL-USER> (eval (read-from-string "`(a b c)"))
(A B C)
But if I want to evaluate the original expression even with local binding for C, there is a problem:
(let ((c 10)) (eval (read-from-string "`(a b ,c)")))
; in: LET ((C 10))
; (LET ((C 10))
; (EVAL (READ-FROM-STRING "`(a b ,c)")))
;
; caught STYLE-WARNING:
; The variable C is defined but never used.
;
; compilation unit finished
; caught 1 STYLE-WARNING condition
; Evaluation aborted on #<UNBOUND-VARIABLE C {1007A3B2F3}>.
This means that EVAL didn't pick up the environment in which C is bound.
PS. Interestingly enough, in Elisp this works.
Backquote
Backquote is a standard macro character in Common Lisp.
In Common Lisp the representation of a backquote expression is undefined. Implementations actually use different representations. What you see for SBCL is implementation specific.
EVAL
The problem you have with eval is fully unrelated to the reader or backquote expressions:
? (let ((c 10))
(eval '(list 'a 'b c)))
Error: The variable C is unbound.
In Common Lisp EVAL is using the dynamic environment and the null lexical environment for evaluation of forms. Above lexical environment, where c is bound to 10, is not used.
But the dynamic binding is. We need to declare the variable to be special:
? (let ((c 10))
(declare (special c))
(eval '(list 'a 'b c)))
(A B 10)
Thus this works, too:
? (let ((c 10))
(declare (special c))
(eval (read-from-string "`(a b ,c)")))
(A B 10)
Emacs Lisp had/has dynamic binding by default (though GNU Emacs now also supports lexical binding). Common Lisp has lexical binding by default.
I store some macros in quoted form (because in fact they produce lambdas with tricky lexical environment and I prefer store and serialize them as lists). So now I'm trying:
(defun play (s)
(funcall (macroexpand s)))
Macroexpand evaluates quoted lambda, so funcall can't run it. How to unquote result of macroexpand without eval? Because in my case it would cause indefensible security hole.
MORE INFO:
What I get look like this (in simplest case):
FUNCALL: #1=#'(LAMBDA (#:G6008) (SYMBOL-MACROLET NIL T)) is not a function name; try using a symbol instead
and symbol-macrolet is what actually builds up "tricky lexical environment" inside lambda.
Macroexpand evaluates quoted lambda, so funcall can't run it. How to
unquote result of macroexpand without eval? Because in my case it
would cause indefensible security hole.
I think that Sylwester's comment about the XY problem is probably right here; it sounds like you're trying to do something that might be done better in a different way. That said, if you have a list that's a lambda expression, you can use coerce to get a function object instead of using eval. That is, you can do this:
CL-USER> (funcall '(lambda () 42))
; Error, like you've been having
CL-USER> (funcall (coerce '(lambda () 42) 'function))
42 ; turned the list (lambda () 42) into a function and called it
This is described in the documentation for coerce; when the "output" type is function, this is what happens with the object argument:
If the result-type is function, and object is any function name that
is fbound but that is globally defined neither as a macro name nor as
a special operator, then the result is the functional value of object.
If the result-type is function, and object is a lambda expression,
then the result is a closure of object in the null lexical
environment.
Thus, if you have a function that returns list of the form (lambda ...), you can use coerce and funcall with its result. This includes macroexpansions, although you may want to use macroexpand-1 rather than macroexpand, because lambda is already a macro, so if you expand too far, (lambda () ...) turns into (function (lambda () ...)).
CL-USER> (defmacro my-constantly (value)
`(lambda () ,value))
MY-CONSTANTLY
CL-USER> (macroexpand-1 '(my-constantly 36))
(LAMBDA () 36)
T
CL-USER> (funcall (coerce (macroexpand-1 '(my-constantly 36)) 'function))
36
If you try that with the plain macroexpand, though, there's a problem. Consider yourself warned:
CL-USER> (macroexpand '(my-constantly 36))
#'(LAMBDA () 36) ; not a list, but a function
T
CL-USER> (funcall (coerce (macroexpand '(my-constantly 36)) 'function))
; Error. :(
I think this is a case where you will find that the REPL is your friend. To get you started:
cl-user> (defmacro foo () #'(lambda () :hi))
foo
cl-user> (foo)
#<Compiled-function (:internal foo) (Non-Global) #x3020014F82FF>
cl-user> (funcall *)
:hi
cl-user> (macroexpand '(foo))
#<Compiled-function (:internal foo) (Non-Global) #x3020014F82FF>
t
cl-user> (funcall *)
:hi
cl-user>
I'll note in passing that the lambda form that appears in your example takes an argument, while your funcall doesn't provide one.
There are several issues with this. First I think this is a XY problem so if you show more of your problem I guess we might find a solution for it.
It has nothing with unquoting since when evaluation a quoted expression it's not longer quoted, but it's turn into data representation of the original quoted expression. You must eval data if you want to run it.
With eval you won't get the current lexical scope. So since you mention eval and lexical environment in the same post makes me thing you won't get what you want.
Now it's no problem making a list of functions, like this:
(list (lambda (x) (+ x x))
This is not quoted since I use list and teh lambda is evaluated to a closure. If it was assigned to variable x you could call it with (funcall (car x) 10)) ; ==> 20
EDIT
I actually made the same error message with this code:
(defmacro test () '#'(lambda (x) x))
(macroexpand '(test)) ; ==> #'(lambda (x) x) ; t
(funcall (macroexpand '(test)) 5) ; ==>
*** - funcall: #'(lambda (x) x) is not a function name; try using a symbol
instead
It doesn't work since you cannot call a lambda unevaluated. You need to call the closure (function) which is the result of the evaluation of the lambda form. If you would instead not quote it you'll have that evaluation in the macro:
(defmacro test () #'(lambda (x) x))
(macroexpand '(test)) ; ==> #<function :lambda (x) x> ;
(funcall (macroexpand '(test)) 5) ; ==> 5
Actually I cannot see why you would need to make this a macro. Lets make it a function instead.
(defun test () #'(lambda (x) x))
(funcall (test) 5 ) ; ==> 5
Even if this was more comples in most cases you would do with a closure.
I am a novice in Lisp, learning slowly at spare time... Months ago, I was puzzled by the error report from a Lisp REPL that the following expression does not work:
((if (> 2 1) + -) 1 2)
By looking around then I knew that Lisp is not Scheme...in Lisp, I need to do either:
(funcall (if (> 2 1) '+ '-) 2 1), or
(funcall (if (> 2 1) #'+ #'-) 2 1)
I also took a glimpse of introductary material about lisp-1 and lisp-2, although I was not able to absort the whole stuff there...in any case, I knew that quote prevents evaluation, as an exception to the evaluation rule.
Recently I am reading something about reduce...and then as an exercise, I wanted to write my own version of reduce. Although I managed to get it work (at least it seems working), I realized that I still cannot exactly explain why, in the body of defun, that some places funcall is needed, and at some places not.
The following is myreduce in elisp:
(defun myreduce (fn v lst)
(cond ((null lst) v)
((atom lst) (funcall fn v lst))
(t (funcall fn (car lst) (myreduce fn v (cdr lst))))))
(myreduce '+ 0 '(1 2 3 4))
My questions are about the 3rd and 4th lines:
The 3rd line: why I need funcall? why not just (fn v lst)? My "argument" is that in (fn v lst), fn is the first element in the list, so lisp may be able to use this position information to treat it as a function...but it's not. So certainly I missed something here.
The 4th line in the recursive call of myreduce: what kind of fn be passed to the recursive call to myreduce? '+ or +, or something else?
I guess there should be something very fundamental I am not aware of...I wanted to know, when I call myreduce as shown in the 6th/last line, what is exactly happening afterwards (at least on how the '+ is passed around), and is there a way to trace that in any REPL environment?
Thanks a lot,
/bruin
Common Lisp is a LISP-2 and has two namespaces. One for functions and one for variables. Arguments are bound in the variable namespace so fn does not exist in the function namespace.
(fn arg) ; call what fn is in the function namespace
(funcall fn ...) ; call a function referenced as a variable
'+ is a symbol and funcall and apply will look it up in the global function namespace when it sees it's a symbol instead of a function object. #'+ is an abbreviation for (function +) which resolves the function from the local function namespace. With lots of calls #'+ is faster than '+ since '+ needs a lookup. Both symbol and a function can be passed as fn to myreduce and whatever was passed is the same that gets passed in line 4.
(myreduce '+ 0 '(1 2 3 4)) ; here funcall might lookup what '+ is every time (CLISP does it while SBLC caches it)
(myreduce #'+ 0 '(1 2 3 4)); here funcall will be given a function object looked up in the first call in all consecutive calls
Now if you pass '+ it will be evaluated to + and bound to fn.
In myreduce we pass fn in the recursion and it will be evaluated to + too.
For #'+ it evaluates to the function and bound to fn.
In myreduce we pass fn in the recursion and it will be evaluated to the function object fn was bound to in the variable namespace.
Common Lisp has construct to add to the function namespace. Eg.
(flet ((double (x) (+ x x))) ; make double in the function namespace
(double 10)) ; ==> 20
But you could have written it and used it on the variable namespace:
(let ((double #'(lambda (x) (+ x x)))) ; make double in the variable namespace
(funcall double 10))
Common Lisp has two (actually more than two) namespaces: one for variables and one for functions. This means that one name can mean different things depending on the context: it can be a variable and it can be a function name.
(let ((foo 42)) ; a variable FOO
(flet ((foo (n) (+ n 107))) ; a function FOO
(foo foo))) ; calling function FOO with the value of the variable FOO
Some examples how variables are defined:
(defun foo (n) ...) ; n is a variable
(let ((n 3)) ...) ; n is a variable
(defparameter *n* 41) ; *n* is a variable
So whenever a variable is defined and used, the name is in the variable namespace.
Functions are defined:
(defun foo (n) ...) ; FOO is a function
(flet ((foo (n) ...)) ...) ; FOO is a function
So whenever a function is defined and used, the name is in the function namespace.
Since the function itself is an object, you can have function being a variable value. If you want to call such a value, then you need to use FUNCALL or APPLY.
(let ((plus (function plus)))
(funcall plus 10 11))
Now why are things like they are? ;-)
two namespaces allow us to use names as variables which are already functions.
Example: in a Lisp-1 I can't write:
(defun list-me (list) (list list))
In Common Lisp there is no conflict for above code.
a separate function namespace makes compiled code a bit simpler:
In a call (foo 42) the name FOO can only be undefined or it is a function. Another alternative does not exist. So at runtime we never have to check the function value of FOO for actually being a function object. If FOO has a function value, then it must be a function object. The reason for that: it is not possible in Common Lisp to define a function with something other than a function.
In Scheme you can write:
(let ((list 42))
(list 1 2 3 list))
Above needs to be checked at some point and will result in an error, since LIST is 42, which is not a function.
In Common Lisp above code defines only a variable LIST, but the function LIST is still available.