如何在 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")
)



谢谢

解决方法

一点反馈

(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 并尝试一些东西,而不是尝试将代码写入编辑器并且从不从 Lisp 获得反馈......

,

这里的答案绝对不是您在现实生活中的做法,但如果您了解它的作用,您就会了解 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(代表“mutant 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)))))

再说一次,这不是你在现实生活中的做法,但如果你了解它的作用以及它是如何做的,你就会理解关于 Lisps 及其理论基础的一件非常重要的事情。这不是他们的全部(甚至不是大部分)有趣的事情,但我认为这是值得理解的事情。