循环遍历数字并检查素数 - 未检测到素数

sef*_* sf 0 lisp primes clisp common-lisp

所以我正在尝试学习 lisp,我想出了一个简单的程序来帮助我学习它,它只是一个检查素数的程序。一开始它起作用了:

(dotimes (i 100)
    (let ((devisors 0)) 
        (if (> i 2) 
            (progn
            (dotimes (j (+ (/ i 2) 1))
            (if (> j 1) 
                (if (= (rem i j) 0) (setq devisors 1) )
            ))
            (if (= devisors 0) (print i))
            )
        )
    )
)
Run Code Online (Sandbox Code Playgroud)

然后我尝试将素数检查抽象为一个函数,并编写了以下代码:

(defun isprime (num) 
    (defvar devisors 0)
    (dotimes (j (+ (/ num 2) 1))
    (if (> j 1) 
        (if (= (rem num j) 0) (setq devisors 1) )
    ))
    (if (= devisors 0) num 0)
)

(dotimes (i 100) 
    (if (/= (isprime i) 0) (print i))
)
Run Code Online (Sandbox Code Playgroud)

但这个不行。它打印 123 并完成。问题是,我尝试只打印 (print (isprime 5)) 并且它可以工作,但在循环中却行不通。

为什么是这样?另请记住,我是 lisp 新手...(如果有帮助的话,我正在使用 clisp)

Chr*_*ris 5

你的第一步应该是分解问题。您需要知道数字范围内的任何内容是否满足表示为谓词函数的条件。这可以通过简单的递归轻松完成,并且自然是尾递归。

(defun any-in-range (s e predicate)
  (cond ((> s e) nil)
        ((funcall predicate s) t)
        (t (any-in-range (+ 1 s) e predicate)))) 
Run Code Online (Sandbox Code Playgroud)

现在检查某个东西是否是素数只是看看某个范围内的任何数字是否是输入数字的约数。范围为 2 到输入数字的平方根。

(defun is-prime (n) 
  (not (any-in-range 2 (floor (sqrt n))
                    (lambda (x) (= 0 (rem n x))))))  
Run Code Online (Sandbox Code Playgroud)
* (is-prime 17)
T
* (is-prime 16)
NIL
Run Code Online (Sandbox Code Playgroud)

现在你可以写:

(dotimes (i 100) 
  (when (is-prime i)
    (print i)))
Run Code Online (Sandbox Code Playgroud)