I assume I must be missing something, rather new to this. Quicklisp update-dist and update-client say I have the latest, loaded cl-ppcre just before and it worked fine. SBCL version is 1.3.8 and I'm on Windows 7, if this is relevant. Any pointers appreciated.
* (ql:quickload :cl-unicode)
To load "cl-unicode":
Load 1 ASDF system:
cl-unicode
; Loading "cl-unicode"
.
; file: C:/Users/K/quicklisp/dists/quicklisp/software/cl-unicode-0.1.5/util.lisp
; in: DEFINE-HANGUL-CONSTANT "SBase"
; (CL-UNICODE::DEFINE-HANGUL-CONSTANT "SBase" 44032)
; --> EVAL-WHEN
; ==>
; (DEFCONSTANT :COMMA
; (CL-UNICODE::CREATE-SYMBOL CL-UNICODE::NAME)
; :COMMA
; CL-UNICODE::VALUE
; :COMMA
; (FORMAT NIL "The constant `~A' from chapter 3 of the Unicode book."
; CL-UNICODE::NAME))
;
; caught ERROR:
; (during macroexpansion of (DEFCONSTANT :COMMA ...))
; error while parsing arguments to DEFMACRO DEFCONSTANT:
; too many elements in
; (:COMMA (CREATE-SYMBOL NAME) :COMMA VALUE :COMMA
; (FORMAT NIL "The constant `~A' from chapter 3 of the Unicode book." NAME))
; to satisfy lambda list
; (SB-IMPL::NAME SB-IMPL::VALUE &OPTIONAL (SB-IMPL::DOC)):
; between 2 and 3 expected, but got 6
; in: DEFINE-HANGUL-CONSTANT "LBase"
; (CL-UNICODE::DEFINE-HANGUL-CONSTANT "LBase" 4352)
; --> EVAL-WHEN
; ==>
; (DEFCONSTANT :COMMA
; (CL-UNICODE::CREATE-SYMBOL CL-UNICODE::NAME)
; :COMMA
; CL-UNICODE::VALUE
; :COMMA
; (FORMAT NIL "The constant `~A' from chapter 3 of the Unicode book."
; CL-UNICODE::NAME))
;
; caught ERROR:
; (during macroexpansion of (DEFCONSTANT :COMMA ...))
; error while parsing arguments to DEFMACRO DEFCONSTANT:
; too many elements in
; (:COMMA (CREATE-SYMBOL NAME) :COMMA VALUE :COMMA
; (FORMAT NIL "The constant `~A' from chapter 3 of the Unicode book." NAME))
; to satisfy lambda list
; (SB-IMPL::NAME SB-IMPL::VALUE &OPTIONAL (SB-IMPL::DOC)):
; between 2 and 3 expected, but got 6
; in: DEFINE-HANGUL-CONSTANT "VBase"
; (CL-UNICODE::DEFINE-HANGUL-CONSTANT "VBase" 4449)
; --> EVAL-WHEN
; ==>
; (DEFCONSTANT :COMMA
; (CL-UNICODE::CREATE-SYMBOL CL-UNICODE::NAME)
; :COMMA
; CL-UNICODE::VALUE
; :COMMA
; (FORMAT NIL "The constant `~A' from chapter 3 of the Unicode book."
; CL-UNICODE::NAME))
;
; caught ERROR:
; (during macroexpansion of (DEFCONSTANT :COMMA ...))
; error while parsing arguments to DEFMACRO DEFCONSTANT:
; too many elements in
; (:COMMA (CREATE-SYMBOL NAME) :COMMA VALUE :COMMA
; (FORMAT NIL "The constant `~A' from chapter 3 of the Unicode book." NAME))
; to satisfy lambda list
; (SB-IMPL::NAME SB-IMPL::VALUE &OPTIONAL (SB-IMPL::DOC)):
; between 2 and 3 expected, but got 6
; in: DEFINE-HANGUL-CONSTANT "TBase"
; (CL-UNICODE::DEFINE-HANGUL-CONSTANT "TBase" 4519)
; --> EVAL-WHEN
; ==>
; (DEFCONSTANT :COMMA
; (CL-UNICODE::CREATE-SYMBOL CL-UNICODE::NAME)
; :COMMA
; CL-UNICODE::VALUE
; :COMMA
; (FORMAT NIL "The constant `~A' from chapter 3 of the Unicode book."
; CL-UNICODE::NAME))
;
; caught ERROR:
; (during macroexpansion of (DEFCONSTANT :COMMA ...))
; error while parsing arguments to DEFMACRO DEFCONSTANT:
; too many elements in
; (:COMMA (CREATE-SYMBOL NAME) :COMMA VALUE :COMMA
; (FORMAT NIL "The constant `~A' from chapter 3 of the Unicode book." NAME))
; to satisfy lambda list
; (SB-IMPL::NAME SB-IMPL::VALUE &OPTIONAL (SB-IMPL::DOC)):
; between 2 and 3 expected, but got 6
; in: DEFINE-HANGUL-CONSTANT "VCount"
; (CL-UNICODE::DEFINE-HANGUL-CONSTANT "VCount" 21)
; --> EVAL-WHEN
; ==>
; (DEFCONSTANT :COMMA
; (CL-UNICODE::CREATE-SYMBOL CL-UNICODE::NAME)
; :COMMA
; CL-UNICODE::VALUE
; :COMMA
; (FORMAT NIL "The constant `~A' from chapter 3 of the Unicode book."
; CL-UNICODE::NAME))
;
; caught ERROR:
; (during macroexpansion of (DEFCONSTANT :COMMA ...))
; error while parsing arguments to DEFMACRO DEFCONSTANT:
; too many elements in
; (:COMMA (CREATE-SYMBOL NAME) :COMMA VALUE :COMMA
; (FORMAT NIL "The constant `~A' from chapter 3 of the Unicode book." NAME))
; to satisfy lambda list
; (SB-IMPL::NAME SB-IMPL::VALUE &OPTIONAL (SB-IMPL::DOC)):
; between 2 and 3 expected, but got 6
; in: DEFINE-HANGUL-CONSTANT "TCount"
; (CL-UNICODE::DEFINE-HANGUL-CONSTANT "TCount" 28)
; --> EVAL-WHEN
; ==>
; (DEFCONSTANT :COMMA
; (CL-UNICODE::CREATE-SYMBOL CL-UNICODE::NAME)
; :COMMA
; CL-UNICODE::VALUE
; :COMMA
; (FORMAT NIL "The constant `~A' from chapter 3 of the Unicode book."
; CL-UNICODE::NAME))
;
; caught ERROR:
; (during macroexpansion of (DEFCONSTANT :COMMA ...))
; error while parsing arguments to DEFMACRO DEFCONSTANT:
; too many elements in
; (:COMMA (CREATE-SYMBOL NAME) :COMMA VALUE :COMMA
; (FORMAT NIL "The constant `~A' from chapter 3 of the Unicode book." NAME))
; to satisfy lambda list
; (SB-IMPL::NAME SB-IMPL::VALUE &OPTIONAL (SB-IMPL::DOC)):
; between 2 and 3 expected, but got 6
; in: DEFINE-HANGUL-CONSTANT "NCount"
; (CL-UNICODE::DEFINE-HANGUL-CONSTANT "NCount"
; (* CL-UNICODE::+V-COUNT+
; CL-UNICODE::+T-COUNT+))
; --> EVAL-WHEN
; ==>
; (DEFCONSTANT :COMMA
; (CL-UNICODE::CREATE-SYMBOL CL-UNICODE::NAME)
; :COMMA
; CL-UNICODE::VALUE
; :COMMA
; (FORMAT NIL "The constant `~A' from chapter 3 of the Unicode book."
; CL-UNICODE::NAME))
;
; caught ERROR:
; (during macroexpansion of (DEFCONSTANT :COMMA ...))
; error while parsing arguments to DEFMACRO DEFCONSTANT:
; too many elements in
; (:COMMA (CREATE-SYMBOL NAME) :COMMA VALUE :COMMA
; (FORMAT NIL "The constant `~A' from chapter 3 of the Unicode book." NAME))
; to satisfy lambda list
; (SB-IMPL::NAME SB-IMPL::VALUE &OPTIONAL (SB-IMPL::DOC)):
; between 2 and 3 expected, but got 6
.
debugger invoked on a UIOP/LISP-BUILD:COMPILE-FILE-ERROR in thread
#<THREAD "main thread" RUNNING {100299C713}>:
COMPILE-FILE-ERROR while compiling #<CL-SOURCE-FILE "cl-unicode/base" "util">
Type HELP for debugger help, or (SB-EXT:EXIT) to exit from SBCL.
restarts (invokable by number or by possibly-abbreviated name):
0: [RETRY ] Retry
compiling #<CL-SOURCE-FILE "cl-unicode/base" "util">.
1: [ACCEPT ] Continue, treating
compiling #<CL-SOURCE-FILE "cl-unicode/base" "util">
as having been successful.
2: Retry ASDF operation.
3: [CLEAR-CONFIGURATION-AND-RETRY] Retry ASDF operation after resetting the configuration.
4: [ABORT ] Give up on "cl-unicode"
5: Exit debugger, returning to top level.
(UIOP/LISP-BUILD:CHECK-LISP-COMPILE-RESULTS NIL T T "~/asdf-action::format-action/" ((#<ASDF/LISP-ACTION:COMPILE-OP > . #<ASDF/LISP-ACTION:CL-SOURCE-FILE "cl-unicode/base" "util">)))
0] 4
;
; compilation unit aborted
; caught 2 fatal ERROR conditions
; caught 7 ERROR conditions
("cl-unicode")
*
Edit: The plot thickens. Now this also happened:
* (ql:quickload "quicklisp-slime-helper")
To load "quicklisp-slime-helper":
Install 3 Quicklisp releases:
alexandria quicklisp-slime-helper slime
; Fetching #<URL "http://beta.quicklisp.org/archive/slime/2016-05-31/slime-v2.18.tgz">
; 1076.19KB
==================================================
1,102,017 bytes in 3.68 seconds (292.28KB/sec)
; Fetching #<URL "http://beta.quicklisp.org/archive/alexandria/2016-08-25/alexandria-20160825-git.tgz">
; 49.63KB
==================================================
50,819 bytes in 0.31 seconds (160.09KB/sec)
; Fetching #<URL "http://beta.quicklisp.org/archive/quicklisp-slime-helper/2015-07-09/quicklisp-slime-helper-20150709-git.tgz">
; 2.16KB
==================================================
2,211 bytes in 0.00 seconds (1079.59KB/sec)
; Loading "quicklisp-slime-helper"
[package swank-loader]..While evaluating the form starting at line 151, column 0
of #P"C:/Users/K/quicklisp/dists/quicklisp/software/slime-v2.18/swank-loader.lisp":
debugger invoked on a SIMPLE-ERROR in thread
#<THREAD "main thread" RUNNING {100299C713}>:
:COMMA is not allowed as a directory component.
Type HELP for debugger help, or (SB-EXT:EXIT) to exit from SBCL.
restarts (invokable by number or by possibly-abbreviated name):
0: [RETRY ] Retry EVAL of current toplevel form.
1: [CONTINUE ] Ignore error and continue loading file "C:\\Users\\K\\quicklisp\\dists\\quicklisp\\software\\slime-v2.18\\swank-loader.lisp
".
2: [ABORT ] Abort loading file "C:\\Users\\K\\quicklisp\\dists\\quicklisp\\software\\slime-v2.18\\swank-loader.lisp".
3: [TRY-RECOMPILING ] Recompile swank-loader and try loading it again
4: [RETRY ] Retry
loading FASL for #<SWANK-LOADER-FILE "swank" "swank-loader">.
5: [ACCEPT ] Continue, treating
loading FASL for #<SWANK-LOADER-FILE "swank" "swank-loader">
as having been successful.
6: Retry ASDF operation.
7: [CLEAR-CONFIGURATION-AND-RETRY] Retry ASDF operation after resetting the
configuration.
8: Give up on "quicklisp-slime-helper"
9: Exit debugger, returning to top level.
(SB-IMPL::IMPORT-DIRECTORY #<unavailable argument> NIL)
0]
In both error messages, the symbol :COMMA plays a role. I just realized I used this symbol in an own program in an earlier experiment to do with part-of-speech tagging. Could this be a problem?
Finally I tried to install babel, which also failed:
* (ql:quickload :babel)
To load "babel":
Load 1 ASDF system:
alexandria
Install 2 Quicklisp releases:
babel trivial-features
; Fetching #<URL "http://beta.quicklisp.org/archive/trivial-features/2015-09-23/trivial-features-20150923-git.tgz">
; 10.26KB
==================================================
10,510 bytes in 0.09 seconds (119.35KB/sec)
; Fetching #<URL "http://beta.quicklisp.org/archive/babel/2015-06-08/babel-20150608-git.tgz">
; 248.03KB
==================================================
253,987 bytes in 1.06 seconds (234.22KB/sec)
; Loading "babel"
[package alexandria]
; file: C:/Users/K/quicklisp/dists/quicklisp/software/alexandria-20160825-git/package.lisp
; in: DEFPACKAGE :ALEXANDRIA
; (DEFPACKAGE :ALEXANDRIA
; ()
; 0
; ()
; DEV
; (:NICKNAMES :ALEXANDRIA)
; (:USE :CL)
; (:LOCK T)
; (:EXPORT #:IF-LET
; #:WHEN-LET
; #:WHEN-LET*
; #:CSWITCH
; #:ESWITCH
; #:SWITCH
; #:MULTIPLE-VALUE-PROG2
; #:NTH-VALUE-OR
; #:WHICHEVER
; #:XOR
; #:DEFINE-CONSTANT
; ...))
;
; caught ERROR:
; (during macroexpansion of (DEFPACKAGE :ALEXANDRIA
; ...))
; bogus DEFPACKAGE option: NIL
debugger invoked on a UIOP/LISP-BUILD:COMPILE-FILE-ERROR in thread
#<THREAD "main thread" RUNNING {100299C713}>:
COMPILE-FILE-ERROR while compiling #<CL-SOURCE-FILE "alexandria" "package">
Type HELP for debugger help, or (SB-EXT:EXIT) to exit from SBCL.
restarts (invokable by number or by possibly-abbreviated name):
0: [RETRY ] Retry
compiling #<CL-SOURCE-FILE "alexandria" "package">.
1: [ACCEPT ] Continue, treating
compiling #<CL-SOURCE-FILE "alexandria" "package">
as having been successful.
2: Retry ASDF operation.
3: [CLEAR-CONFIGURATION-AND-RETRY] Retry ASDF operation after resetting the
configuration.
4: [ABORT ] Give up on "babel"
5: Exit debugger, returning to top level.
(UIOP/LISP-BUILD:CHECK-LISP-COMPILE-RESULTS NIL T T "~/asdf-action::format-action/" ((#<ASDF/LISP-ACTION:COMPILE-OP > . #<ASDF/LISP-ACTION:CL-SOURCE-FILE "alexa
ndria" "package">)))
0] 4
;
; compilation unit aborted
; caught 2 fatal ERROR conditions
; caught 1 ERROR condition
(:BABEL)
Edit 2: Just did the same in Linux (Mint 18 VBox) and received the same versions:
* (ql:system-apropos "unicode")
#<SYSTEM cl-ppcre-unicode / cl-ppcre-2.0.11 / quicklisp 2016-08-25>
#<SYSTEM cl-ppcre-unicode-test / cl-ppcre-2.0.11 / quicklisp 2016-08-25>
#<SYSTEM cl-unicode / cl-unicode-0.1.5 / quicklisp 2016-08-25>
#<SYSTEM cl-unicode/base / cl-unicode-0.1.5 / quicklisp 2016-08-25>
#<SYSTEM cl-unicode/build / cl-unicode-0.1.5 / quicklisp 2016-08-25>
#<SYSTEM cl-unicode/test / cl-unicode-0.1.5 / quicklisp 2016-08-25>
#<SYSTEM hu.dwim.syntax-sugar/unicode / hu.dwim.syntax-sugar-20160318-darcs / quicklisp 2016-08-25>
*
Only thing I need to know, am I missing something I should know or is it borked? I want to work with it and learn Lisp, not fix installation issues.
Edit 3: Thanks to the hint to check integrity of the readtable, it now works:
* (setq *readtable* (copy-readtable nil))
#<READTABLE {100569BA23}>
* (ql:quickload :cl-unicode)
To load "cl-unicode":
Install 1 Quicklisp release:
cl-unicode
; Fetching #<URL "http://beta.quicklisp.org/archive/cl-unicode/2014-12-17/cl-unicode-0.1.5.tgz">
; 474.62KB
==================================================
486,011 bytes in 1.80 seconds (264.27KB/sec)
; Loading "cl-unicode"
[package cl-unicode]..............................
[package cl-unicode-names]....................
(:CL-UNICODE)
*
It remains a mystery why the old version of cl-unicode keeps getting pulled, and why the same problem occurred on another box with no history of tinkering. But I'm satisfied for now. Thanks to all who took the time to respond.
Related
(defun add-1-all (list)
(mapcar #'1+ '(list))
)
I am trying to pass a list of integers and add 1 to each integer in the list with mapcar, but I keep getting list is defined but never used.
; in: DEFUN ADD-1-ALL
; (DEFUN ADD-1-ALL (LIST) (MAPCAR #'1+ '(LIST)))
; --> SB-IMPL::%DEFUN SB-IMPL::%DEFUN SB-INT:NAMED-LAMBDA
; ==>
; #'(SB-INT:NAMED-LAMBDA ADD-1-ALL
; (LIST)
; (BLOCK ADD-1-ALL (MAPCAR #'1+ '(LIST))))
;
; caught STYLE-WARNING:
; The variable LIST is defined but never used.
;
; compilation unit finished
; caught 1 STYLE-WARNING condition
Since you're quoting (list), this is a list containing the literal symbol list, it not the value of the variable. That's why you get a warning about an unused variable.
And when you run it, you'll get an error because 1+ requires its argument to be a number, not the symbol list.
The second argument to mapcar should be the value of the list itself, so just used the variable directly.
(defun add-1-all (list)
(mapcar #'1+ list)
)
Lisp can be interactively used.
Just type '(list) to the read eval print loop:
* '(list)
(LIST)
* (describe '(list))
(LIST)
[list]
So you see that '(list) gets evaluated to a list (LIST).
You have written the list as literal data.
A variable is in Lisp an unquoted symbol, here just list.
When parsing syntax from a string input port, all line/column numbers get set to #f. Why is that?
(let* ([port (open-input-string "123")]
[stx (read-syntax "my-input" port)])
(printf "line ~a column ~a" (syntax-line stx) (syntax-column stx))
)
Expected output:
line 1 column 0
Actual output:
line #f column #f
You have to explicitly turn on line based location tracking for ports, for example by setting the port-count-lines-enabled parameter:
(parameterize ([port-count-lines-enabled #t])
(let* ([port (open-input-string "123")]
[stx (read-syntax "my-input" port)])
(printf "line ~a column ~a" (syntax-line stx) (syntax-column stx))))
which prints
line 1 column 0
There's also port-count-lines! for enabling it on existing ports.
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.
In sbcl, I know I can muffle the anticipated messages when using both &optional and &key in defun, but that doesn't seem to work in defmacro. (I should just redesign/rewrite, I know, but this is legacy code.)
When I compile this file ...
(declaim (sb-ext:muffle-conditions style-warning))
(defun wilma (&optional wilma1 &key wilma2 wilma3)
(declare (ignore wilma1 wilma2 wilma3)))
(defmacro betty (&optional betty1 &key betty2 betty3)
(declare (ignore betty1 betty2 betty3)))
... this happens:
home:~/sbcl/experiments/style-warning.d$ sbcl --noinform
* (compile-file "5.lisp")
; compiling file "/u/home/sbcl/experiments/style-warning.d/5.lisp" (written 09 OCT 2017 03:31:44 PM):
; compiling (DECLAIM (MUFFLE-CONDITIONS STYLE-WARNING))
; compiling (DEFUN WILMA ...)
; compiling (DEFMACRO BETTY ...)
; file: /u/home/sbcl/experiments/style-warning.d/5.lisp
; in: DEFMACRO BETTY
; (DEFMACRO BETTY (&OPTIONAL BETTY1 &KEY BETTY2 BETTY3)
; (DECLARE (IGNORE BETTY1 BETTY2 BETTY3)))
;
; caught STYLE-WARNING:
; &OPTIONAL and &KEY found in the same lambda list: (&OPTIONAL BETTY1 &KEY BETTY2
; BETTY3)
;
; compilation unit finished
; caught 1 STYLE-WARNING condition
; /u/home/sbcl/experiments/style-warning.d/5.fasl written
; compilation finished in 0:00:00.018
#P"/u/home/sbcl/experiments/style-warning.d/5.fasl"
T
NIL
* (exit)
home:~/sbcl/experiments/style-warning.d$
How do I suppress these diagnostics?
EDIT 1:
Since this is legacy code and I'll just massage it for sbcl-readiness and then leave it alone, there's no reason I can't do something like this in any code which uses it:
home:~/sbcl/experiments/style-warning.d$ sbcl --noinform
* (with-open-file (*error-output* "/dev/null" :direction :output :if-exists :append)
(compile-file "5.lisp"))
; compiling file "/u/home/sbcl/experiments/style-warning.d/5.lisp" (written 09 OCT 2017 03:31:44 PM):
; compiling (DECLAIM (MUFFLE-CONDITIONS STYLE-WARNING))
; compiling (DEFUN WILMA ...)
; compiling (DEFMACRO BETTY ...)
; /u/home/sbcl/experiments/style-warning.d/5.fasl written
; compilation finished in 0:00:00.017
#P"/u/home/sbcl/experiments/style-warning.d/5.fasl"
T
NIL
* (exit)
home:~/sbcl/experiments/style-warning.d$
But is there something out there which can suppress style warnings in macro definitions?
You need to run
(declaim (sb-ext:muffle-conditions style-warning))
before the form (defmacro betty ...) is compiled.
One way to do that is
$ sbcl --non-interactive --eval '(declaim (sb-ext:muffle-conditions style-warning))' --eval '(compile-file "5")'
This is SBCL 1.4.0, an implementation of ANSI Common Lisp.
More information about SBCL is available at <http://www.sbcl.org/>.
SBCL is free software, provided as is, with absolutely no warranty.
It is mostly in the public domain; some portions are provided under
BSD-style licenses. See the CREDITS and COPYING files in the
distribution for more information.
; compiling file "/Users/sds/lisp/5.lisp" (written 09 OCT 2017 09:51:51 PM):
; compiling (DEFUN WILMA ...)
; compiling (DEFMACRO BETTY ...)
; /Users/sds/lisp/5.fasl written
; compilation finished in 0:00:00.010
where the file 5.lisp only contains wilma and betty:
(defun wilma (&optional wilma1 &key wilma2 wilma3)
(declare (ignore wilma1 wilma2 wilma3)))
(defmacro betty (&optional betty1 &key betty2 betty3)
(declare (ignore betty1 betty2 betty3)))
I am new to LISP and want to understand, how to write LISP macro code, which evaluates all forms but returns output of only one specified form, where the form to be returned could be specified inside macro or can be a user provided input.
I used following macro and it returns the output of the second form. but it doesn't seem correct, as it doesn't seem to evaluate the first form and I would like to specify which of the two forms to evaluate.
(defmacro testcode () (+ 3 4) (+ 5 6))
(macroexpand-1 (testcode))
11
NIL
Macros are syntactical abstractions or syntax sugaring. testcode does it's calculations in macro expansion time and thus you cannot expect the forms to be calculated more than once and (testcode) is synonymous with the "code" 11. To illustrate that lets give it side effects:
(defmacro testcode ()
(print "expanding testcode")
(+ 3 4) ; dead code. Never gets used
(+ 5 6))
(defun test ()
(testcode))
; prints "expanding testcode"
(test)
; ==> 11 (doesn't print anything)
(test)
; ==> 11 (still doesn't print anything, Why?)
(disassemble 'test)
; ==>
; 0 (const 0) ; 11
; 1 (skip&ret 1)
So test literally is the same as (defun (test) 11).
So what are macros? Well if you have written this and noticed there is a pattern:
(let ((it (heavy-cpu-function var)))
(when it
(do-something-with-it it)))
You can say this is a thing I create syntax for:
(defmacro awhen (predicate-expression &body body)
`(let ((it ,predicate-expression))
(when it
,#body)))
(macroexpand-1 '(awhen (heavy-cpu-function var)
(do-something-with-it it)))
; ==>
; (let ((it (heavy-cpu-function var)))
; (when it
; (do-something-with-it it)))
So instead of writing the first you use awhen and Common Lisp changes it to the first. You are using a lot of macros since a lot of syntax in Common Lisp are macros:
(macroexpand-1 '(and (a) (b) (c)))
; ==>
; (cond ((not (a)) nil)
; ((not (b)) nil)
; (t (c)))
(macroexpand-1 '(cond ((not (a)) nil)
((not (b)) nil)
(t (c)))
; ==>
; (if (not (a))
; nil
; (if (not (b))
; nil
; (c)))