Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Lisp: Help NOT returning a value?

I have written a function which accepts a list of strings, and prints them line-by-line.

(defun print-to-lines (slist)
    (cond
        ((null slist) slist)
        (t (let ((empty (write-line (car slist)))) (print-to-lines (cdr slist))))))

This works great, except there is an extra return value (in this case NIL) at the end of the output (when run in the debugging window):

CG-USER(16): (print-to-lines '("adam" "emilio" "eoln"))
adam
emilio
eoln
NIL

I understand where that extra NIL comes from (it is the return value of my function), but I want it to not be there. My assignment dictates that this is not present. Is there a way to "fake" it or disable this?

like image 845
Adam S Avatar asked Mar 26 '11 19:03

Adam S


4 Answers

You can use values without arguments to return no values, i.e. (values).

More idiomatic versions of your function could be written with mapc or dolist instead of explicit recursion (but you would still need the (values) because mapc returns the list and dolist returns nil).

like image 151
Rörd Avatar answered Nov 10 '22 14:11

Rörd


I want to dissect and improve your code while providing answers to your questions along the lines.

Standard indentation is two spaces.

(defun print-to-lines (slist)
  (cond
    ((null slist) slist)
    (t (let ((empty (write-line (car slist)))) (print-to-lines (cdr slist))))))

You are allowed to make newlines between any two tokens.

(defun print-to-lines (slist)
  (cond
    ((null slist) slist)
    (t (let ((empty (write-line (car slist))))
         (print-to-lines (cdr slist))))))

The stuff after a condition in a cond form is evaluated in an implicit progn. You do not need to name the value that is thrown away anyway.

(defun print-to-lines (slist)
  (cond
    ((null slist) slist)
    (t (write-line (car slist))
       (print-to-lines (cdr slist)))))

In order to return nothing, use values. Note that this is usually not necessary, as the return value is not part of the output; it is just displayed by the REPL (in a syntax highlighting environment, program output and REPL output are usually different colours). Note as an aside that values can also be used to return multiple values.

(defun print-to-lines (slist)
  (cond
    ((null slist) (values))
    (t (write-line (car slist))
       (print-to-lines (cdr slist)))))

Note that explicit recursion is not needed here. Some other, more concise ideas:

(defun print-to-lines (slist)
  (dolist (string slist)
    (write-line string)))

(defun print-to-lines (slist)
  (mapcar #'write-line slist))

(defun print-to-lines (slist)
  (format t "~{~a~%~}" slist))
like image 41
Svante Avatar answered Nov 10 '22 14:11

Svante


Maybe this will help:

http://coding.derkeiler.com/Archive/Lisp/comp.lang.lisp/2010-08/msg00553.html

like image 40
Ilya Kogan Avatar answered Nov 10 '22 12:11

Ilya Kogan


Firstly, in this case, it's not an extra return value. You are printing to *STDOUT* and the repl is also printing to *STDOUT* so it just looks like it is. If your function were to print to *FILE* instead, you wouldn't be having this problem.

your code returns null because of line three

1: (defun print-to-lines (slist)
2:   (cond
3:     ((null slist) slist)
4:     (t (let ((empty (write-line (car slist)))) (print-to-lines (cdr slist))))))

In the case of slist being null you are returning slist hence the nul return value. You could rewrite the function so that rather than returning the null slist it returns another value ( say a function call to write-line or some such).

Additionally look into the format function.

like image 33
zellio Avatar answered Nov 10 '22 12:11

zellio