0

I have this small program that prints triangles either forwards or backwards depending on whether the input is positive or negative. It works perfectly, except at the end of every loop it prints NIL. I tried changing the bounds of the loop, but every when I do it effects the size of the triangle. Is there any solution to this? Please find the code below.

(defun triangle(k) 
    (cond ((or(not(integerp k)) (= k 0)) '("invalid number; please enter a positive or a negative integer"))
          ((< k -1) 
             (loop for x from k to -1 do
                 (loop for y from k to -1 do 
                       (if (< y x) 
                           (princ #\Space)
                           (princ '*) 
                       ) 
                     
                  ) 
                (terpri)
              )
          )  
        
         ((or (= k 1) (= k -1)) '*) 
         (t(loop  for x from 0 to k do 
               (loop for y from 0 to k do  
                 (if (< x y)    
                     (princ '*) 
                 )
                ) 
                (terpri)
           ) 
         ) 
    ) 
)
10
  • The REPL prints the value returned by the function. Since the function doesn't return anything explicitly, it returns NIL by default. Commented Nov 2, 2020 at 20:11
  • That has nothing to do with what your function does. You can just ignore it. Commented Nov 2, 2020 at 20:12
  • is there any way to remove it at all? like how would I change the implementation so i does not return nill? Commented Nov 2, 2020 at 20:21
  • 1
    Try returning (VALUES) at the end of the function. Commented Nov 2, 2020 at 20:35
  • 1
    The lack of proper formatting of your code is making the code unreadable. Commented Nov 2, 2020 at 21:38

2 Answers 2

2
(defun triangle (k) 
  (cond ((or (not (integerp k))
             (= k 0))
         '("invalid number; please enter a positive or a negative integer"))
        ((< k -1) 
         (loop for x from k to -1 do
               (loop for y from k to -1 do 
                     (if (< y x) 
                         (princ #\Space)
                       (princ '*))) 
                (terpri)))
        ((or (= k 1) (= k -1))
         '*) 
        (t
         (loop for x from 0 to k do 
               (loop for y from 0 to k do  
                     (if (< x y)    
                         (princ '*))) 
               (terpri))))
  (values))

Example:

CL-USER 8 > (triangle 3)
***
**
*


CL-USER 9 > 
Sign up to request clarification or add additional context in comments.

3 Comments

I still receive NIL at the end of this when I put (print (triangle 3))
@abdcg: why would you PRINT the result of a call to triangle? The function triangle already itself prints the triangle -> you are calling the functions PRINC and TERPRI inside TRIANGLE.
Thank you, works perfectly now, did not think about that!
1

I know that it is off topic, considering your question was about loops, but i would propose to separate data generation, manipulation and representation, which is always a good practice. You could make a single triangle generator, and then invert it, if needed. It could look like this, for example:

(defun mk-tri (n)
  (when (plusp n)
    (loop for i from 1 to n
          collect (nconc (loop repeat i collect #\*)
                         (loop repeat (- n i) collect #\space)))))

(defun print-field (field)
  (format t "~{~{~a~}~%~}" field))

(print-field (mk-tri 5))
;; *    
;; **   
;; ***  
;; **** 
;; *****

(defun invert-v (data)
  (reverse data))

(print-field (invert-v (mk-tri 5)))
;; *****
;; **** 
;; ***  
;; **   
;; *    

(defun invert-h (data)
  (mapcar #'reverse data))

(print-field (invert-h (mk-tri 5)))
;;     *
;;    **
;;   ***
;;  ****
;; *****

this would give you the whole new level of freedom, like you can imagine this little toolkit for patterns drawing:

(defun concat-v (d1 d2)
  (append d1 d2))

(defun concat-h (d1 d2)
  (mapcar #'append d1 d2))

(defun repeat-v (n data)
  (reduce #'concat-v (loop repeat n collect data)))

(defun repeat-h (n data)
  (reduce #'concat-h (loop repeat n collect data)))

(let* ((tri (mk-tri 5))
       (tri2 (concat-v tri (invert-v tri)))
       (rect (concat-h tri2 (invert-h tri2))))
  (print-field (repeat-v 2 (repeat-h 3 rect))))
;; *        **        **        *
;; **      ****      ****      **
;; ***    ******    ******    ***
;; ****  ********  ********  ****
;; ******************************
;; ******************************
;; ****  ********  ********  ****
;; ***    ******    ******    ***
;; **      ****      ****      **
;; *        **        **        *
;; *        **        **        *
;; **      ****      ****      **
;; ***    ******    ******    ***
;; ****  ********  ********  ****
;; ******************************
;; ******************************
;; ****  ********  ********  ****
;; ***    ******    ******    ***
;; **      ****      ****      **
;; *        **        **        *

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.