Как сделать цикл в lisp?

Только начал изучать и кодировать lisp, я пытаюсь создать программу, которая будет постоянно принимать число и останавливаться только тогда и только тогда, когда последнее введенное число вдвое больше предыдущего числа.

Вот мой код

 


----------


(let((a 0)
     (b 0)
     (count 0))
(loop
   (= a b))
   (princ"Enter Number: ")
   (defvar a(read))
   (format t "~% a = ~d" a)
   (setq count (1+ count))
(while
   (!= b(* a 2) || <= count 1)
   (princ "Program Terminated Normally")
)



Спасибо


person Sharmaine Cstll    schedule 29.01.2021    source источник
comment
Прочтите Common Lisp HyperSpec и документацию SBCL. SBCL написан в основном на Common Lisp и имеет открытый исходный код, так что изучайте его исходный код и черпайте из него вдохновение.   -  person Basile Starynkevitch    schedule 29.01.2021
comment
Пожалуйста, размещайте текст, а не изображения.   -  person Renzo    schedule 29.01.2021


Ответы (2)


Вот ответ, который определенно не соответствует тому, как вы поступили бы в реальной жизни, но если вы понимаете, что он делает, вы поймете одну из двух важных вещей в Lisps.

(Если вы понимаете, почему эквивалентная программа не будет надежно работать в Scheme, вы также поймете одну из важных вещей, касающихся написания безопасных программ! К счастью, это Common Lisp, а не Scheme, так что здесь все в порядке. )

Прежде всего, давайте напишем небольшую вспомогательную функцию для чтения целых чисел. Это просто мелочь: это не важно.

(defun read-integer (&key (prompt "Integer: ")
                          (stream *query-io*))
  ;; Read an integer.  This is just fiddly details
  (format stream "~&~A" prompt)
  (values (parse-integer (read-line stream))))

Хорошо, теперь вот немного странная функция под названием mu (что означает «мутант U»):

(defun mu (f &rest args)
  (apply f f args))

А теперь вот наша программа:

(defun read-integers-until-double-last ()
  (mu (lambda (c getter current next factor)
        (if (= next (* current factor))
            (values current next)
          (mu c getter next (funcall getter) factor)))
      #'read-integer
      (read-integer)
      (read-integer)
      2))

И вот это работает:

> (read-integers-until-double-last)
Integer: 0
Integer: 4
Integer: 3
Integer: -2
Integer: -4
-2
-4

Для большей таинственности вы можете существенно расширить вызовы mu здесь, что сделает его либо более ясным, либо менее ясным: я не совсем уверен, какой именно:

(defun read-integers-until-double-last ()
  ((lambda (c)
     (funcall c c 
              #'read-integer
              (read-integer)
              (read-integer)
              2))
   (lambda (c getter current next factor)
     (if (= next (* current factor))
         (values current next)
       (funcall c c getter next (funcall getter) factor)))))

Опять же, это не то, как вы делаете это в реальной жизни, но если вы понимаете, что это делает и как это делается, вы поймете довольно важную вещь о Лиспах и их теоретических основах. Это не все (даже не большинство) интересных вещей о них, но, я думаю, это стоит понять.

person Community    schedule 29.01.2021
comment
Я попробовал ваш код в Repl.it, он работает, но программа не завершается, когда целые числа удваиваются последними. я не знаю почему - person Sharmaine Cstll; 04.02.2021
comment
@Sharmaine: я не знаю, что делает repl.it (возможно, это ненадежно). Однако мой ответ на самом деле был задуман как «если вы это понимаете, то вы достигли просветления в церкви ботаников», а не что-то действительно практическое: ответ Райнера Йосвига намного лучше! - person ; 04.02.2021

немного обратной связи

(let ((a 0)
      (b 0)
      (count 0))
 (loop
   (= a b))      ; here the LOOP is already over.
                 ;  You have a closing parenthesis
                 ;   -> you need better formatting
   (princ"Enter Number: ")
   (defvar a(read))
   (format t "~% a = ~d" a)
   (setq count (1+ count))
(while
   (!= b(* a 2) || <= count 1)
   (princ "Program Terminated Normally")
)

некоторое улучшенное форматирование:

(let ((a 0)
      (b 0)
      (count 0))
  (loop
   (= a b))                  ; LOOP ends here, that's not a good idea
  (princ "Enter Number: ")
  (defvar a(read))           ; DEFVAR is the wrong construct,
                             ;   you want to SETQ an already defined variable
  (format t "~% a = ~d" a)
  (setq count (1+ count))
  (while                     ; WHILE does not exist as an operator
   (!= b(* a 2) || <= count 1)    ; This expression is not valid Lisp
   (princ "Program Terminated Normally")
   )

Возможно, вам придется еще немного изучить операторы Лиспа, прежде чем вы действительно сможете писать такие циклы. Вы также можете использовать Lisp в интерактивном режиме и пробовать что-то, вместо того, чтобы пытаться писать код в редакторе и никогда не получать обратную связь от Lisp...

person Rainer Joswig    schedule 29.01.2021