0

I'm trying to create a function that will take a string and display it.

(defun closing (s)
  (format t "~{~a~}" ("Sincerely," "\n" s)))

What I hope to get is

Sincerely,

Frank

if "Frank" is the string I passed in. It complains of the variable S is defined but never used. What am I doing wrong?

Trying to use format alone: If I declare urname as a defparameter to be "Frank", the following doesn't print Frank, rather just the variable name. (Without quote it complains of urname not being a function.)

(format t "~{~a~}" '(urname urname urname))

How can I feed variables to format?

3
  • See the LIST function: (list x y z) Commented Sep 18, 2015 at 16:41
  • 1
    @melpomene Not absolutely sure, but I don't think list is needed here; ~@{ will use the remaining arguments. Commented Sep 18, 2015 at 16:47
  • @melpomene This worked, but why? Commented Sep 18, 2015 at 16:49

2 Answers 2

4

There are three issues here: (1) The code you posted doesn't just have the problem of not using s; it's also trying to call the string "Sincerely" as a function; (2) quoting a list means you'll get exactly what's quoted (e.g., a list of symbols, not a list of values of variables); (3) calling format with lists.

(something other-stuff...) is a function call

When I put the code you posted into SBCL, I get some very specific and helpful output:

CL-USER> (defun closing (s)
           (format t "~{~a~}" ("Sincerely," "\n" s)))
; in: DEFUN CLOSING
;     ("Sincerely," "n" S)
; 
; caught ERROR:
;   illegal function call

;     (SB-INT:NAMED-LAMBDA CLOSING
;         (S)
;       (BLOCK CLOSING (FORMAT T "~{~a~}" ("Sincerely," "n" S))))
; 
; caught STYLE-WARNING:
;   The variable S is defined but never used.
; 
; compilation unit finished
;   caught 1 ERROR condition
;   caught 1 STYLE-WARNING condition

("Sincerely," "\n" s) is an illegal function call, since a string, like "Sincerely", can't have a function binding. Since SBCL sees the problem in that, it recognizes that the one thing that s might have been used for (i.e., an argument to a function call), can't happen. That's why you'll get the error, and then the associated style warning.

Creating lists of values

The second is probably answered in other questions already, but the short answer is that you want (list x y z), not '(x y z). The former calls the function list with the values of the variables x, y, and z, while the latter denotes a literal list of the symbols x, y, and z.

CL-USER> (let ((a 42)
               (b 89))
           (print '(a b))               ; a list of two symbols
           (print (list a b)))          ; a list of two numbers
(A B) 
(42 89) 

Format, iteration, &c.

The third is probably more interesting, since format has so many possibilities. The ~{ and ~} in your example are used for iterating over values in a list. First, let's look at a simple example: you can just use the format directive ~a and call format with the arguments you want to splice in:

CL-USER> (let ((closing "Sincerely")
               (name "Frank"))
           (format t "~a,~%~a" closing name))
Sincerely,
Frank

Now, if you need to print multiple values, you can use ~{ and ~} to have format iterate over a list of values:

CL-USER> (let ((closing "Sincerely")
               (names '("Frank" "John")))
           (format t "~a,~{~%~a~}" closing names))
Sincerely,
Frank
John

If the names are the values of variables, then you can either create a list containing those values:

CL-USER> (let ((closing "Sincerely")
               (name1 "Frank")
               (name2 "John"))
           (format t "~a,~{~%~a~}" closing (list name1 name2)))
Sincerely,
Frank
John

or you can change ~{ to ~@{ and have format read the remaining arguments as the list:

CL-USER> (let ((closing "Sincerely")
               (name1 "Frank")
               (name2 "John"))
           (format t "~a,~@{~%~a~}" closing name1 name2))
Sincerely,
Frank
John
Sign up to request clarification or add additional context in comments.

Comments

2

You should read a tutorial about format, from here for example

For an easy explanation

(format (destination-stream usually t for standard output nil to form a string) (here comes the string) (&rest variables that should write in the string where is an ~A and by position like String.format in java or c))

in your case, you need the symbol ~% or use the character for return in common lisp

CL-USER> (defun closing (s) (format t "~A~%~%~A" "Sincerely," s))
CLOSING
CL-USER> (closing "paco")
Sincerely,

paco
NIL

The nil say that the functions returns null, and the other is the standard output if you want to return a string, put nil instead of t

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.