SBCL 2.3.7
I want to save me from writing a format like this because I have a lot of variables (more than 3) and want to insert a semicolon between them:
(format nil "~a;~b;~c;" var1 var2 var3)
Expected result:
"a;b;c;"
I have defined a special variable and a macro.
(defparameter *delimiter* ";")
(defmacro format-delimited (stream fmt delimiter &body vars)
(let ((fmtstr ""))
(dotimes (i (length vars))
(setf fmtstr (str:concat fmtstr fmt delimiter)))
`(format ,stream ,fmtstr ,@vars)))
This call successfully returns:
(format-delimited nil "~a" ";" "a" "b" "c")
"a;b;c;"
macroexpand-1 returns:
(FORMAT NIL "~a;~a;~a;" "wolf" "golf" "rolf")
This call ends in error:
(format-delimited nil "~a" *delimiter* "a" "b" "c")
; Debugger entered on #<TYPE-ERROR expected-type: SEQUENCE datum: *DELIMITER*>
macroexpand-1 also ends in error.
What is the cause of the error?
I see you use str:concat
, so you can use (str:join ";" '("wolf" "golf"))
(you don't need a macro).
str:join
takes two arguments: the delimiter and a list of strings. If you want to write a varying number of strings without a list, like so:
(join-all ";" "wolf" "golf" "rolf" etc etc etc)
we can write a helper function. It will accept &rest arguments:
(defun join-all (delimiter &rest strings)
(funcall #'str:join delimiter strings))
=>
(JOIN-ALL ";" "golf" "wolf" "rolf")
"golf;wolf;rolf"
funcall
allows to call a function by name with its right number of arguments. The varying number of strings are grouped as a list thanks to &rest strings
, so we can pass this list as argument to str:join
.