I'm trying to create a shorthand for lambda using underbar (_), per:
(defmacro _ (&rest body)
`(lambda (&rest _) ,@(expand_s body)))
(defun expand_s (s)
(cond ((null s) nil)
((atom s)
(if (eq '_ s) '(nth 0 _)
(let ((s_string (format nil "~a" s)))
(if (char-equal #\_ (aref s_string 0))
`(nth ,(1- (parse-integer (subseq s_string 1))) _)
s))))
(t (cons (expand_s (car s)) (expand_s (cdr s))))))
(print (macroexpand '(_ (+ _1 _2))))
(print (mapcar (_ (+ (* _1 _2) (expt _2 _1))) '(1 2 3) '(10 20 30)))
Ugly as it is, it works fine compiled in SBCL:
* (load "shlambda.fasl")
#'(LAMBDA (&REST _) (+ (NTH 0 _) (NTH 1 _)))
(20 440 27090)
But the SBCL compiler really doesn't like it:
; compiling (PRINT (MAPCAR # ...))
; file: shlambda.lisp
; in:
; PRINT (MAPCAR (_ (+ (* |_1| |_2|) (EXPT |_2| |_1|))) '(1 2 3) '(10 20 30))
; (_ (+ (* |_1| |_2|) (EXPT |_2| |_1|)))
; --> FUNCTION + * NTH SB-C::%REST-REF AND IF
; ==>
; NIL
;
; caught STYLE-WARNING:
; This is not a NUMBER:
; NIL
; See also:
; The SBCL Manual, Node "Handling of Types"
;
; caught STYLE-WARNING:
; This is not a NUMBER:
; NIL
; See also:
; The SBCL Manual, Node "Handling of Types"
; --> FUNCTION + EXPT NTH SB-C::%REST-REF AND IF
; ==>
; NIL
;
; caught STYLE-WARNING:
; This is not a NUMBER:
; NIL
; See also:
; The SBCL Manual, Node "Handling of Types"
;
; caught STYLE-WARNING:
; This is not a NUMBER:
; NIL
; See also:
; The SBCL Manual, Node "Handling of Types"
;
; compilation unit finished
; caught 4 STYLE-WARNING conditions
I guess type inference can't figure out the types of an &rest in a lambda (which, I admit, I'm amazed that it even accepts an &rest in a lambda!) But you can pretty much never figure out the types in an &rest, so ... ???
Thanks in advance for your guidance.
The following compiles entirely silently for me, in a cold SBCL 2.2.7:
(defmacro _ (&rest body) ;should be &body
`(lambda (&rest _) ,@(expand_s body)))
(eval-when (:load-toplevel :compile-toplevel :execute)
;; needed on voyage
(defun expand_s (s)
(cond ((null s) nil)
((atom s)
(if (eq '_ s) '(nth 0 _)
(let ((s_string (format nil "~a" s)))
(if (char-equal #\_ (aref s_string 0))
`(nth ,(1- (parse-integer (subseq s_string 1))) _)
s))))
(t (cons (expand_s (car s)) (expand_s (cdr s)))))))
(print (macroexpand '(_ (+ _1 _2))))
(print (mapcar (_ (+ (* _1 _2) (expt _2 _1))) '(1 2 3) '(10 20 30)))
And I can't see why it should not. Barmar is right that the &rest
in the macro should probably be &body
but that's stylistic.
My guess is that you might not be defining expand_s
early enough (see my eval-when
), but actually I have no idea.