Common Lisp отображает числа в слова - PullRequest
0 голосов
/ 13 марта 2019

Я пытаюсь создать функцию перевода, которая берет список чисел `(1 2 3) и пишет (" ОДИН "," ДВА "," ТРИ "). Вот что у меня есть:

(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))

Если я пытаюсь запустить это, я получаю эту ошибку, которую я не смог выяснить:

*** - RETURN-FROM: no block named NIL is currently visible

Есть идеи? Спасибо.

Ответы [ 3 ]

8 голосов
/ 13 марта 2019

return не делает то, что делает на других языках:] Вы ищете return-from translate-number, но это не идиоматично.

Во-первых, знаете ли вы, что функция format имеет~R "римская" директива?

(format nil "~R" 1) ;; => one

Если вы действительно хотите использовать заглавные буквы, используйте string-upcase или директиву формата ~( ... ~) с модификаторами @::

(format nil "~@:(~R~)" 1)
;; "ONE"

https://lispcookbook.github.io/cl-cookbook/strings.html#to-upper-case--

CL краткий справочник с директивами формата: http://clqr.boundp.org/

Итак:

(mapcar (lambda (nb) 
          (format nil "~@:(~R~)" nb))
        '(1 2 3))
("ONE" "TWO" "THREE")

Для многих if подряд вы можетеиспользуйте case или cond.

(defun translate-number (num)
   (case num
     (1 "ONE")
     (2 "FOO")))

Нет необходимости в пустоте () для второй формы if.

https://learnxinyminutes.com/docs/common-lisp/;)

3 голосов
/ 13 марта 2019
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"
3 голосов
/ 13 марта 2019

Вы возвращаетесь в свои операторы if из пустого списка (NIL) после оператора return.Нет блока с именем nil, но пустой список вернет nil.Вместо этого вы можете использовать (return-from block-name (optiopnal-Statement)) at для условия else в каждом из ваших блоков if.Еще одна проблема - ваш дизайн здесь.Вместо использования нескольких операторов if с оператором return для каждого из них вы можете создать блок cond вместо нескольких операторов if.Но было бы еще разумнее использовать оператор case в вашей функции translate-number.Если вы собираетесь использовать множественные операторы if, учитывающие блок cond, и в тех случаях, когда это не делается с тех пор (обычно, когда вы хотите вернуть значение в зависимости от типа аргумента, передаваемого в функцию)), рассмотрите оператор case.Операторы if становятся повторяющимися, как вы можете видеть.Вот пример, чтобы у вас не было возврата nil:

(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")
...