Reputation:
I am trying to make a translate function that takes a list of numbers `(1 2 3) and writes ("ONE" "TWO" "THREE"). Here's what I have so far:
(defun translate-number (num)
(if (= num 0) (return "ZERO") ())
(if (= num 1) (return "ONE") ())
(if (= num 2) (return "TWO") ())
(if (= num 3) (return "THREE") ())
(if (= num 4) (return "FOUR") ())
(if (= num 5) (return "FIVE") ())
(if (= num 6) (return "SIX") ())
(if (= num 7) (return "SEVEN") ())
(if (= num 8) (return "EIGHT") ())
(if (= num 9) (return "NINE") ())
)
(defun translate (L)
(mapcar #'translate-number L)
)
(translate `(1 2 3))
If I try to run this, I get this error that I have not been able to figure out:
*** - RETURN-FROM: no block named NIL is currently visible
Any ideas? Thanks.
Upvotes: 0
Views: 776
Reputation: 139261
CL-USER > (getf '(1 "ONE" 2 "TWO" 3 "THREE" 4 "FOUR" 5 "FIVE"
6 "SIX" 7 "SEVEN" 8 "EIGHT" 9 "NINE")
2
:dont-know)
"TWO"
CL-USER > (aref #("ZERO" "ONE" "TWO" "THREE" "FOUR"
"FIVE" "SIX" "SEVEN" "EIGHT" "NINE")
2)
"TWO"
Upvotes: 3
Reputation: 18375
return
doesn't do what it does in other languages :] You are looking for return-from translate-number
, but this is not idiomatic.
First, did you know that the format
function has a ~R
"roman" directive ?
(format nil "~R" 1) ;; => one
If you really want uppercase, use string-upcase
or the format directive ~( ... ~)
with the modifiers @:
:
(format nil "~@:(~R~)" 1)
;; "ONE"
https://lispcookbook.github.io/cl-cookbook/strings.html#to-upper-case--
CL quick reference with format directives: http://clqr.boundp.org/
So:
(mapcar (lambda (nb)
(format nil "~@:(~R~)" nb))
'(1 2 3))
("ONE" "TWO" "THREE")
For many if
in a row you can use case
or cond
.
(defun translate-number (num)
(case num
(1 "ONE")
(2 "FOO")))
No need of void ()
for the second form of if
.
https://learnxinyminutes.com/docs/common-lisp/ ;)
Upvotes: 8
Reputation: 2190
You're returning within your if statements from an empty list (NIL) after a return statement. There is no block named nil, but an empty list will return nil. Instead, you could use a (return-from block-name (optiopnal-statement)) at for the else condition in each of your if blocks. Another issue is your design pattern here. Instead of using multiple if statements, with a return statement for each one, you can instead create a cond block, in place of multiple if statements. But, it would make even more sense to use a case statement within your translate-number function. If you are going to use multiple if statements consider a cond block, and where that doesn't make since (usually when you want to return a value depending on the type of argument passed to a function)) consider a case statement. The if statements become repetitive as you can see. Here is an example so that you don't have a nil return-from:
(defun translate-number(num)
(case num
(1 "ONE")
(2 "TWO")
(3 "THREE")
(4 "FOUR")
(5 "FIVE")
(6 "SIX")
(7 "SEVEN")
(8 "EIGHT")
(9 "NINE")))
(defun translate(&rest nums)
(apply #'mapcar #'translate-number nums))
(translate '(1 2 3))
("ONE" "TWO" "THREE")
Upvotes: 3