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)
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;"
(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