My recursive call seems to not be working, I am trying to make a triangle given an integer, and with the help of you guys I was finally able to make the string print on the same line, the correct amount of times for 1 line. At the end of printing the line, I have a recursive call that calls on triangle to make another line, one character shorter. This call seems to never be reached for some reason. Please find the code below, thank you all in advance for any and all help, it is all greatly appreciated!
Note: On a side note, is there any way to stop a function in Lisp similar to a return statement? I would like for the recursion to stop at k = 1, and not continue to k = 0.
(defun newTriangle (k)
(cond ((<= k 0) (princ '(Nope)))
((or (= k 1) (= k -1)) (princ 'a))
((> k 0) (make-string k :initial-element #\a))
(newTriangle (- k 1))))
(print (newTriangle 3))
sample output triangle(3)
aaa
aa
a
sample output triangle(-3)
aaa
aa
a
First, you need to decide exactly what it is that newTriangle
is doing. The call (print (newTriangle 3))
suggests that newTriangle
should return a string, which is then printed by the call to print
. But, the OP definition of newTriangle
is both printing output, and returning a single line of the triangle as a string.
The recursive call to newTriangle
is never reached because all possible cases for the value of k
are exhausted before this line is reached. Since k
can only be less than zero, equal to zero, or greater than zero, and since all of these cases are tested for before reaching the recursive call, it is never reached. Also note that the OP code has the syntax wrong for the final part of the cond
statement. The first expression in a cond
branch is a test, and the convention is to use t
here for a branch that will always be evaluated if reached. But, this many cases are not needed here.
Assuming the newTriangle
function should not return a string, but should print a triangle as a side-effect, what should it do? If the input number is greater than 0, it should print a line with a number of characters equal to the input number and then call itself with the input reduced by one; otherwise it should do nothing:
(defun print-triangle (k)
(when (> k 0)
(princ (make-string k :initial-element #\a))
(terpri)
(print-triangle (- k 1))))
This definition is named print-triangle
to emphasize that it prints a triangle as a side-effect, and because kebab-case is idiomatic in Lisps, and camelCase is not. Note that each time that print-triangle
is called with input greater than zero, a string of the correct length is printed, and then a newline is printed (with the obscurely-named terpri
, which just writes a newline to the current output stream), before calling print-triangle
again with k
reduced by 1.
Sample REPL interaction:
CL-USER> (print-triangle 3)
aaa
aa
a
NIL
If the goal is instead to return a string, one approach would be to call a helper function that keeps the result in a parameter:
(defun new-triangle (k)
(build-triangle k ""))
(defun build-triangle (k result)
(if (> k 0)
(build-triangle (- k 1)
(concatenate 'string
result
(make-string k :initial-element #\a)
(string #\newline)))
result))
Here, new-triangle
takes an integer argument, and calls build-triangle
, passing both the integer argument and an empty string in the result
position. The build-triangle
function operates much the same as print-triangle
before, but instead of printing the lines, they are concatenated with result
, along with a string containing a newline. When build-triangle
is finished, the result
string is returned to new-triangle
. Note that simply calling new-triangle
from the REPL will print the resulting string as data (i.e., with quotation marks); calling print
on the result of new-triangle
will both print the string as data, and return the string. To see the string printed without quotation marks, format
can be used; or you could use princ
which will print the string without quotation marks, and return the string itself:
CL-USER> (new-triangle 3)
"aaa
aa
a
"
CL-USER> (print (new-triangle 3))
"aaa
aa
a
"
"aaa
aa
a
"
CL-USER> (format t "~A" (new-triangle 3))
aaa
aa
a
NIL
CL-USER> (princ (new-triangle 3))
aaa
aa
a
"aaa
aa
a
"