I am writing a program where each time I access the value of a boolean, no matter how it's accesed, it's value inverts (even if just printing it). In an OOP language the way I would accomplish this would by defining an accessor/getter function for this method. How can I accomplish this in common lisp.
Here is some example code I have written using lisp macros which outputs the expected values, but requires all references to be wrapped like this (A). It would also require me to define a new macro for each boolean. If possible I would like to avoid these two issues.
#!/bin/clisp
(defun getval(x)
(set x (not (eval x)))
(return-from getval (eval x)))
(setq a_private 'nil)
(defmacro A() (getval 'a_private))
(format t "A -> ~d~%" (A))
(format t "A -> ~d~%" (A))
(format t "A -> ~d~%" (A))
(format t "A -> ~d~%" (A))
; this returns the following:
; A -> T
; A -> NIL
; A -> T
; A -> NIL
From my understanding, you want to have some variables which toggle from TRUE to FALSE. From the code snippet above I don't really understand what is going on, so I will make the proposals below, I do hope you will find the one which suits you well.
Keep it simple and use simple boolean values
(defparameter var1 nil)
(defparameter var2 nil)
(format t "== SIMPLE WAY == ~%")
(format t "STEP 1~%")
(format t "A -> ~A~%" var1)
(format t "B -> ~A~%" var2)
(setf var1 (not var1))
(setf var2 (not var2))
(format t "STEP 2~%")
(format t "A -> ~A~%" var1)
(format t "B -> ~A~%" var2)
(setf var1 (not var1))
(setf var2 (not var2))
(format t "STEP 3~%")
(format t "A -> ~A~%" var1)
(format t "B -> ~A~%" var2)
You want to go further and dive into the world of structures
(format t "== STRUCT AND FUNCTIONS == ~%")
(defstruct status
(flag nil))
;; function to toggle the 'flag' from structure of type 'status'
;; Returns the new status
(defun toggle-flag (status-object)
(let ((previous-flag (status-flag status-object))) ;; get the current flag
(let ((new-flag (not previous-flag))) ;; calculate the new flag
(setf (status-flag status-object) new-flag) ;; update the new flag
;; return value
new-flag)))
(defparameter var1 (make-status)) ;; create a new object status
(defparameter var2 (make-status)) ;; create a new object status
(format t "STEP 1~%")
(format t "A -> ~A~%" (status-flag var1))
(format t "B -> ~A~%" (status-flag var2))
(format t "STEP 2~%")
(format t "A -> ~A~%" (toggle-flag var1))
(format t "B -> ~A~%" (toggle-flag var2))
(format t "STEP 3~%")
(format t "A -> ~A~%" (toggle-flag var1))
(format t "B -> ~A~%" (toggle-flag var2))
You likes OOP adventures and you want to use classes and methods
(format t "== CLASSES == ~%")
(defclass state () ;; define a new class 'state'
((flag ;; with a field 'flag'
:accessor state-flag ;; accessible with the function (state-flag)
:initform nil))) ;; initialized with nil
;; Method to toggle the 'flag' from object of type 'state'
;; Will return the new status
(defmethod toggle ((object state))
(let ((previous-status (state-flag object)))
(let ((new-status (not previous-status)))
(setf (state-flag object) new-status)
;; return value
new-status)))
(defparameter var1 (make-instance 'state)) ;; create a new object state
(defparameter var2 (make-instance 'state)) ;; create a new object state
(format t "STEP 1~%")
(format t "A -> ~A~%" (state-flag var1))
(format t "B -> ~A~%" (state-flag var2))
(format t "STEP 2~%")
(format t "A -> ~A~%" (toggle var1))
(format t "B -> ~A~%" (toggle var2))
(format t "STEP 3~%")
(format t "A -> ~A~%" (toggle var1))
(format t "B -> ~A~%" (toggle var2))
All these examples should give you the expected result:
STEP 1
A -> NIL
B -> NIL
STEP 2
A -> T
B -> T
STEP 3
A -> NIL
B -> NIL
The last option I could provide would be to use amazing closures:
(defun make-toggler ()
(let ((flag nil)) ;; create a new variable (available only to the closure)
(lambda () ;; return a function... which toggle the variable!
(setf flag (not flag))
;; return value
flag)))
(defparameter var1 (make-toggler))
(defparameter var2 (make-toggler))
(format t "STEP 1~%")
(format t "A -> ~A~%" (funcall var1))
(format t "B -> ~A~%" (funcall var2))
(format t "STEP 2~%")
(format t "A -> ~A~%" (funcall var1))
(format t "B -> ~A~%" (funcall var2))
(format t "STEP 3~%")
(format t "A -> ~A~%" (funcall var1))
(format t "B -> ~A~%" (funcall var2))
Related
I am trying to do the following: separate a function that gets values from some user input from the function that uses it.
I have tried the following code for the proof of concept initially (that worked):
(defun initialiser (bindings)
(cl-loop for (var) in bindings do
(set var (read-from-minibuffer "Input value: "))))
That i have tested with:
(let ((name))
(initialiser '((name)))
(message "name is %S" name))
The idea was to pass bindings to the function that handles input in the form like ((name "Name") (address "Post address") (code "County code")) or something similar, and in there assign the input.
After testing above i have come up with the following macro to do things:
(defmacro initialise-and-execute (bindings initialiser &rest callback-actions)
(let ((unwrapped-bindings (map 'list (lambda (binding) (car binding)) bindings)))
`(let ,unwrapped-bindings
(,initialiser (quote ,bindings)
(lambda () ,#callback-actions)))))
However, in the "real" scenario the assignments must happen in callbacks, like:
(defun initialiser(bindings)
(cl-loop for (var) in bindings collect
(lambda () (set var (read-from-minibuffer "Input value: ")))
into callbacks
return callbacks))
This fails to work. Code i have used to test was:
(defvar callbacks nil)
(let ((name))
(setq callbacks (initialiser '((name)))))
(funcall (car callbacks))
Edit: changed the code the following way:
(defmacro initialise-and-execute (bindings initialiser &rest callback-actions)
(let ((unwrapped-bindings (map 'list (lambda (binding) (car binding)) bindings)))
`(lexical-let ,unwrapped-bindings
(,initialiser
(quote ,(map 'list
(lambda (binding) (list (cadr binding)
`(lambda (val) (setq ,(car binding) val))))
bindings))
(lambda () ,#callback-actions)))))
What it must do: generate number of lambdas that share the same lexical environment - one that uses captured variables and the rest that modify them.
However, what i get is, regrettably, something else. Symbols used in callback-actions do not resolve into the values set.
For completeness, here is how i tested it:
(defun init-values (bindings callback)
(loop for (desc setter) in bindings
for idx = 0 then (incf idx)
do (print (format "Setting %s" desc))
(funcall setter idx))
(funcall callback))
(initialise-and-execute
((name "Name")
(surname "Surname"))
init-values
(message "name is %S" name))
Here, lambdas were not generated in a loop and values in the context of a lexical binding were assigned with setq.
To set the function value, use fset, not set.
(defun initialiser(bindings)
(cl-loop for (var) in bindings collect
(lambda () (fset var (read-from-minibuffer "Input value: ")))
into callbacks
return callbacks))
There are possible issues:
in a LOOP the VAR is possibly assigned on each iteration, not bound (that's in Common Lisp). so your callbacks set all the same VAR value.
in a lexical bound Lisp (new in GNU Emacs Lisp) one can't set the variable values with SET
Examples:
ELISP> (mapcar #'funcall
(cl-loop for i in '(1 2 3 4)
collect (lambda () i)))
(4 4 4 4)
all closures have the same value of i
ELISP> (let ((a 'foobar))
(set 'a 42)
a)
foobar
SET had no effect on the local variable
In Common Lisp I might write something like:
(defun initializer (bindings)
(loop for (what setter) in bindings
for new-value = (progn
(format t "Enter ~a: " what)
(finish-output)
(read-line))
do (funcall setter new-value)))
(defmacro call-with-bindings (name-sym-list fn)
(let ((value-sym (gensym "v")))
`(,fn
(list ,#(loop for (name sym) in name-sym-list
collect `(list ,name ,`(lambda (,value-sym)
(setf ,sym ,value-sym))))))))
CL-USER > (let (name age)
(call-with-bindings (("name" name) ("age" age))
initializer)
(format t "name is ~S~%" name)
(values name age))
Enter name: Lara
Enter age: 42
name is "Lara"
"Lara"
"42"
Where we can look at the macro expansion:
CL-USER > (pprint (macroexpand-1
'(call-with-bindings (("name" name) ("age" age))
initializer)))
(INITIALIZER (LIST (LIST "name"
(LAMBDA (#:|v1669|)
(SETF NAME #:|v1669|)))
(LIST "age"
(LAMBDA (#:|v1669|)
(SETF AGE #:|v1669|)))))
After some experimenting, i have been able to do it. The key was realising that lexical-let apparently had some restrictions on how the lambda should be placed for them to have the same closure context. After i have managed to generate set of closures that referred to the same variables, the rest was easy.
Here is the final code:
(defmacro make-lamba-set (bindings &rest callback-actions)
"Make set of closures with shared context
BINDINGS are a list of form (SYMBOL NAME), where SYMBOL is not defined yet
CALLBACK-ACTIONS are forms that use symbols from bindings
Return created captures a as a list of forms:
(do-callback-actions (set-symbol NAME) ...)"
(let ((unwrapped-bindings (map 'list
(lambda (binding)
(car binding))
bindings)))
`(lexical-let ,unwrapped-bindings
(list (lambda () ,#callback-actions)
,#(map 'list
(lambda (binding)
`(list
(lambda (val)
(setq ,(car binding) val))
,(cadr binding)))
bindings)))))
(defmacro initialise-and-execute (bindings initialiser &rest callback-actions)
"BINGINGS have form of ((BINDING-SYMBOL PROMPT) ...)
INITIALISER somehow assigns values to all of BINDING-SYMBOL
then it calls CALLBACK-ACTIONS with values of BINDING-SYMBOL set"
`(let ((closure-parts (make-lamba-set ,bindings ,#callback-actions)))
(,initialiser (cdr closure-parts)
(car closure-parts))))
Here is how i tested it:
(defun init-values (bindings callback)
(loop for (setter desc) in bindings
for idx = 0 then (incf idx)
do (message "Setting %s" desc)
(funcall setter idx))
(funcall callback))
(initialise-and-execute ((name "Name")
(surname "Surname"))
init-values
(insert (format "Name is %S and surname is %S"
name
surname)))
That gave me expected output of:
Name is 0 and surname is 1
Emacs-lisp is default using call-by-value, but I'm trying use its symbol mechanism to simulate call-by-reference.
For example,
(setq lexical-binding nil)
(defun cbr (x)
(message "cbr (symbol-name x) %s" (symbol-name x))
(message "cbr (symbol-value x) %s" (symbol-value x))
(set x 2))
(let ((a 1))
(cbr 'a)
a)
;; cbr (symbol-name x) a
;; cbr (symbol-value x) 1
;; 2
It works well, because the result of let expression is 2, so it is indeed the call-by-reference behavior.
However, if I change the name from a to x:
(let ((x 1))
(cbr 'x)
x)
;; cbr (symbol-name x) x
;; cbr (symbol-value x) x
;; 1
Now it doesn't work as expected anymore.
Why?
Notice that it even can not get the correct symbol-name in cbr.
I think I have known what happen.
The second program returns 1, because the symbol x is captured by cbr's param x. When the body of cbr is evaluated, there are two bindings in the environment: one is the let binding x = 1, the other is x = x which is created by cbr's application. The symbol x in the (set x 2) uses the later one.
A workaround of this question is:
(let ((gen-x (gensym)))
(set gen-x 1)
(cbr gen-x)
(symbol-value gen-x))
;; cbr (symbol-name x) g36
;; cbr (symbol-value x) 1
;; 2
What should be clear from this is that relying on dynamic scope and symbol-value is a disaster: you need gensyms all over the place. Relying on dynamic scope for anything is generally a disaster, except in the specific, rare but extremely useful, case where you actually want dynamic scope.
But solving this problem trivial, even in elisp, with lexical scope. Here is one simple approach:
(defmacro ref (form)
;; Construct a reference to a form
(unless lexical-binding
(error "doomed"))
(let ((<setting> (gensym)))
`(lambda (&rest ,<setting>) ;hack for &optional (v nil vp)
(cond
((null ,<setting>)
,form)
((null (cdr ,<setting>))
(setf ,form (car ,<setting>)))
(t
(error "mutant"))))))
(defun ref-value (ref)
(funcall ref))
(defun set-ref-value (ref value)
;; should be (setf ref-value), but elisp
(funcall ref value))
And now, for instance, given:
(defun outer (v)
(let ((x 1))
(princ (format "x is first %s\n" x))
(inner (ref x) v)
(princ (format "and x is now %s\n" x))
x))
(defun inner (ref v)
(princ (format " ref is first %s\n" (ref-value ref)))
(set-ref-value ref v)
(princ (format " and ref is now %s\n" (ref-value ref))))
Then
ELISP> (outer 4)
x is first 1
ref is first 1
and ref is now 4
and x is now 4
4 (#o4, #x4, ?\C-d)
I am trying to make a toy system for writing documents using a macro (doc):
Example #1:
(doc id: 1
title: "First document"
"First sentence."
"Second sentence.")
Intended expansion:
(make-doc (list (list 'id: 1) (list 'title: "First document"))
(list "First sentence" "Second sentence"))
Example #2:
(let ((my-name "XYZ"))
(doc title: "Second document"
id: (+ 1 1)
"First sentence."
(string-append "My name is " my-name ".")
"Last sentence."))
Intended expansion:
(let ((my-name "XYZ"))
(make-doc (list (list 'title: "Second document") (list 'id: (+ 1 1)))
(list "First sentence."
(string-append "My name is " my-name ".")
"Last sentence.")))
More sample calls to this macro are:
(doc id: 1 "First sentence." "Second sentence.")
(doc id: 1 title: "First document" subtitle: "First subdocument"
"First sentence." "Second sentence." "Third sentence.")
First come the metadata specs, then sentences. Metadata must come before the sentences. The macro must accept any number of metadata specs.
Evaluating (doc ...) should return a string, or write the resulting text into a file. But I have not yet implemented this functionality, because I am stuck on the definition of the doc macro (which is the point of this question).
Below is my implementation of the doc macro. Vocabulary: title: "ABC" and id: 123 are called "metadata"; title: and id: are called "metadata IDs".
;;; (metadata-id? 'x:) -> #t
;;; (metadata-id? 'x) -> #f
;;; (metadata-id? "Hi!") -> #f
(define (metadata-id? x)
(cond [(symbol? x)
(let* ([str (symbol->string x)]
[last-char (string-ref str (- (string-length str) 1))])
(char=? last-char #\:))]
[else #f]))
;;; (pair-elements '(1 2 3 4 5)) -> '((1 2) (3 4) (5)).
(define (pair-elements l [acc '()] [temp null])
(cond [(and (null? l) (null? temp)) acc]
[(null? l)
(append acc (list (list temp)))]
[(null? temp)
(pair-elements (cdr l) acc (car l))]
[else
(pair-elements (cdr l)
(append acc (list (list temp (car l)))))]))
(define-syntax doc
(syntax-rules ()
((doc arg . args)
(let* ([orig-args (cons 'arg 'args)]
[metadata-bindings (takef (pair-elements orig-args)
(lambda (e)
(metadata-id? (car e))))]
[sentences (drop orig-args (* 2 (length metadata-bindings)))])
(make-doc metadata-bindings sentences)))))
(define (make-doc metadata-bindings sentences)
;; Do something ...
;; Placeholder stubs:
(writeln metadata-bindings)
(writeln sentences))
Using this implementation, evaluating example #1 prints as expected:
((id: 1) (title: "First document"))
("First sentence." "Second sentence.")
However, evaluating example #2 prints:
((id: (+ 1 1)) (title: "Second document"))
("First sentence." (string-append "My name is " my-name ".") "Last sentence.")
Apparently, the arguments were not evaluated. The expected result of example #2 is supposed to be this instead:
((id: 2) (title: "Second document"))
("First sentence." "My name is XYZ." "Last sentence.")
What is wrong with the implementation of the doc macro? How can I make the macro evaluate some of its arguments?
The reason is that you're quoting 'args, which results in it being an s-expression after macro expansion, not evaluated with function application. To fix this, you probably want make use of quasiquote. This'll also require you to rework how you specify the macro pattern. I suggest using the ... notation. Here's a sketch of what I'm describing:
(define-syntax doc
(syntax-rules ()
[(doc arg rest-args ...)
(let* ([orig-args `(arg ,rest-args ...)]
; the rest is the same
))]))
I'm not sure if this is the proper way, but I've managed to write a helper macro parse-args using syntax-case in Racket. It works like this:
(parse-args title: "Interesting document"
id: (+ 1 2)
"First sentence."
(string-append "Second sentence" "!")
"Last sentence.")
The above gets transformed into a list:
'((metadata title: "Interesting document")
(metadata id: 3)
(sentences "First sentence."
"Second sentence!"
"Last sentence."))
Implementation:
(begin-for-syntax
;;; (metadata-id? 'x:) -> #t; (metadata-id? 'x) -> #f.
(define (metadata-id? x)
(cond [(symbol? x)
(let* ([str (symbol->string x)]
[last-char (string-ref str (- (string-length str) 1))])
(char=? last-char #\:))]
[else #f])))
(define-syntax (parse-args stx)
(syntax-case stx ()
[(_ arg1 arg2) ; If no sentences.
(metadata-id? (syntax->datum (syntax arg1)))
(syntax `((metadata arg1 ,arg2)))]
[(_ arg1 arg2 rest-args ...)
(metadata-id? (syntax->datum (syntax arg1)))
(syntax `((metadata arg1 ,arg2) ,#(parse-args rest-args ...)))]
[(_ sentence rest-sentences ...)
(syntax (list `(sentences ,sentence ,rest-sentences ...)))]))
Notice how I used a "fender" ((metadata-id? (syntax->datum (syntax arg1)))). This is the crucial feature missing in syntax-rules macros, which is why I implemented the macro using syntax-case instead.
Now that I am able to parse the arguments, all that remains is to use parse-args in the definition of doc.
(define-syntax (doc stx)
(syntax-case stx ()
((doc arg rest-args ...)
(syntax (apply make-doc
(group-args (parse-args arg rest-args ...)))))))
group-args rearranges the list returned by parse-args like so:
(group-args '((metadata a: 1)
(metadata b: 2)
(sentences "ABC" "DEF")))
;; Returns:
;; '(((a: 1)
;; (b: 2))
;; ("ABC" "DEF"))
;; The car is an assoc list of metadata.
;; The cadr is the list of sentences.
Implementation:
;;; 'lst' is valid even if there is no 'metadata'.
;;; 'lst' is valid even if there is no 'sentences'.
;;; However, if there is a 'sentences', it must be the last item in the list.
(define (group-args lst [metadata-acc '()])
(define tag-name car)
(define remove-tag cdr)
(cond [(null? lst) (list metadata-acc '())]
[(eq? 'metadata (tag-name (car lst)))
(group-args (cdr lst)
(cons (remove-tag (car lst))
metadata-acc))]
[(eq? 'sentences (tag-name (car lst)))
(cons metadata-acc
(list (remove-tag (car lst))))]
[else
(error "Invalid values" lst)]))
make-doc can now be defined like this:
;;; 'metadata' is an assoc list of metadata.
;;; 'sentences' is a list of strings.
(define (make-doc metadata sentences)
;; ... create the document ...
;; Placeholder stubs:
(display "ID: ")
(displayln (cadr (assq 'id: metadata)))
(display "Title: ")
(displayln (cadr (assq 'title: metadata)))
(displayln sentences))
Usage:
(let ((my-name "XYZ"))
(doc title: "Second document"
id: (+ 1 1)
"First sentence."
(string-append "My name is " my-name ".")
"Last sentence."))
Prints:
ID: 2
Title: Second document
(First sentence. My name is XYZ. Last sentence.)
I would recommend you to use the syntax/parse library, since it's so much easier to write this kind of macro with it.
#lang racket
(require syntax/parse/define)
(define (make-doc x y) `(make-doc ,x ,y))
(begin-for-syntax
;; metadata-id? :: symbol? -> boolean?
(define (metadata-id? x)
(define str (symbol->string x))
(define len (string-length str))
;; Need to check that len > 0.
;; Otherwise, the empty identifier (||)
;; would cause an "internal" error
(and (> len 0)
(char=? (string-ref str (sub1 len)) #\:)))
(define-splicing-syntax-class key-val-class
(pattern (~seq key:id val:expr)
#:when (metadata-id? (syntax-e #'key)))))
(define-simple-macro (doc key-val:key-val-class ... xs ...)
(make-doc (list (list (quote key-val.key) key-val.val) ...)
(list xs ...)))
;;;;;;;;;;;;;;;;;
(doc id: 1
title: "First document"
"First sentence."
"Second sentence.")
;; '(make-doc ((id: 1) (title: "First document")) ("First sentence." "Second sentence."))
(let ([my-name "XYZ"])
(doc title: "Second document"
id: (+ 1 1)
"First sentence."
(string-append "My name is " my-name ".")
"Last sentence."))
;; '(make-doc
;; ((title: "Second document") (id: 2))
;; ("First sentence." "My name is XYZ." "Last sentence."))
(let ([|| 1])
(doc || 2))
;; '(make-doc () (1 2))
How to do auto input in multiple read-line?
(let ((out (with-output-to-string (*standard-output*)
(let ((*standard-input* (make-string-input-stream "y y")))
(when (find (read-line) '("yes" "y" "t") :test #'string-equal)
(print "aaaaa"))
(when (find (read-line) '("yes" "y" "t") :test #'string-equal)
(print "bbbbbb"))
))))
out)
I try like this, and I get:
; Evaluation aborted on #<END-OF-FILE {10048FD503}>.
This code work with read, but I need with read-line.
Another possibility is to use the parameter of read-line that requires to return nil on end of file:
(let ((out (with-output-to-string (*standard-output*)
(let ((*standard-input* (make-string-input-stream "y y")))
(when (find (read-line *standard-input* nil) '("yes" "y" "t") :test #'string-equal)
(print "aaaaa"))
(when (find (read-line *standard-input* nil) '("yes" "y" "t") :test #'string-equal)
(print "bbbbbb"))))))
out)
I made it work like this:
(with-output-to-string (*standard-output*)
(with-input-from-string (*standard-input* (format nil "y~%y"))
(when (find (read-line) '("yes" "y" "t") :test #'string-equal)
(print "aaaaa"))
(when (find (read-line) '("yes" "y" "t") :test #'string-equal)
(print "bbbbbb"))))
The without-to-string is unnecessary for an example...
CL-USER 177 > (flet ((yes-p (input-string &aux (yes-words '("yes" "y" "t")))
"returns T when the input-string is one of yes, y or t."
(find input-string yes-words :test #'string-equal)))
(with-input-from-string (*standard-input* (format nil "y~%y"))
(when (yes-p (read-line))
(print "aaaaa"))
(when (yes-p (read-line))
(print "bbbbbb"))
(values)))
"aaaaa"
"bbbbbb"
I try to do a very simple thing in Lisp - to find a way to turn on a global valuable nodebug t and then some of debug format form would be silence. To do that, I found I cannot grasp the difference of the following:
(defparameter *nodebug* t)
(setf x 1)
;;; the basic function
(format t "x is ~a" x) ;;; generate -> x is 1
;;; try to use function not macro
(defun formatdf (stream string &rest allparm) ;;; later add (if ...
(format stream string allparm))
(formatdf t "x is ~a" x) ;;; generate -> x is (1)
;;; try to use macro
(defmacro formatdm (stream string &rest allparm) ;;; later add (if ...
(format stream string allparm))
(formatdm t "x is ~a" x) ;;; generate -> x is (X)
It seems the generated code (or the function one) is not the same as the original format form. What should be my next step?
(defmacro formatdm (stream string &rest allparm) ;;; later add (if ...
(format stream string allparm))
A macro should return source code, not execute. Here it is only useful to see what the value of allparm is at macro expansion time. It is a part of the source code: (x).
You need to return a list with the necessary instructions - here the code to call format.
This is a very good book about Lisp, which also should explain the basics of macros: http://www.cs.cmu.edu/~dst/LispBook/
The problem of your "function one" is that you pass &rest parameter to the format function as is. Passing x to formatdf results in the creating a list containing one parameter, that is bound to allparm.
So if you want to just print the first parameter you should write:
(formatdf t "x is ~a" (car x))
or fix format inside formatdf in the next way:
(apply #'format stream string allparm)
(defparameter nodebug t)
(setf x 1)
(format t "x is ~a" x) ;;; generate -> x is 1
;;; to generate the same and prepare for nodebug version, the following is needed:
;;; using defmacro
(defmacro formatdmadv (stream string &rest allparm)
`(format ,stream ,string ,#allparm))
(formatdmadv t "formatdmadv x is ~a" x) ;;; generate -> x is 1 <-- macro correct
;;; or using defun as suggested
(formatdf_car t "formatdf_car x is ~a" x) ;;; generate -> x is 1 <-- fun correct
(defun formatdf (stream string &rest allparm)
(apply #'format (list* stream string allparm)))
(formatdf t "formatdf using apply x is ~a" x) ;;; generate -> x is 1 <-- fun correct
;;; ---- the below is incorrect
(defun formatdf_err (stream string &rest allparm) (format stream string allparm))
(formatdf_err t "formatdf_err: x is ~a" x) ;;; generate -> x is (1)
(defun formatdf_car (stream string &rest allparm)
(format stream string (car allparm)))
(defmacro formatdm (stream string &rest allparm)
(format stream string allparm))
(formatdm t "formatdm x is ~a" x) ;;; generate -> x is (X)
;;; ----- test confirming the findings
(pprint (macroexpand-1 '(formatdm t "formatdm x is ~a" x)))
(pprint (macroexpand '(formatdm t "formatdm x is ~a" x)))
(pprint (macroexpand-1 '(formatdm t "formatdm b" c)))
;;; --- incorrect one and do not even generate the source code even
(pprint (macroexpand-1 '(formatdmadv t "formatdmadv x is ~a" x)))
(pprint (macroexpand '(formatdmadv t "formatdmadv x is ~a" x)))
(pprint (macroexpand-1 '(formatdmadv t "formatdmadv b" c)))