Lisp 函数(OccurencesOfPrimes<;list>;),用于统计(可能嵌套的)列表中的素数

Lisp 函数(OccurencesOfPrimes<;list>;),用于统计(可能嵌套的)列表中的素数,lisp,common-lisp,Lisp,Common Lisp,我正在解决一个问题,以便在lisp中的列表中获取素数的出现次数。 输入: 编写一个函数(occurrencesofprimes),计算(可能是嵌套的)列表中的primes数 输出:示例:(primes(((1)(2))(5)(3)((8)3))的发生次数返回4 我正在使用以下代码,但出现如下错误: ( defun OccurencesOfPrimes (list) (loop for i from 2 to 100 do ( setq isPrime

我正在解决一个问题,以便在lisp中的列表中获取素数的
出现次数
。 输入: 编写一个函数(
occurrencesofprimes
),计算(可能是嵌套的)列表中的primes数

输出:示例:
(primes(((1)(2))(5)(3)((8)3))的发生次数返回4

我正在使用以下代码,但出现如下错误:

(

defun OccurencesOfPrimes (list)
        (loop for i from 2 to 100 
            do ( setq isPrime t)
            (loop for j from 2 to i
                never (zerop (mod i j))
                    (setq isPrime f)
                    (break)
            )
        )
        (if (setq isPrime t)
            (append list i)
        )
        )
    )

LOOP: illegal syntax near (SETQ ISPRIME F) in
(LOOP FOR J FROM 2 TO I NEVER (ZEROP (MOD I J)) (SETQ ISPRIME F) (BREAK)
)


任何帮助。

保持格式与语言的预期约定一致非常重要。它有助于阅读代码(尤其是与其他程序员一起阅读),并可以帮助您查看错误

此外,您应该使用一个编辑器,它至少可以跟踪括号。在Emacs中,当您将光标放在第一个左括号中时,匹配的括号将亮显。你可以发现,你有一个额外的括号,没有任何用途

(

defun OccurencesOfPrimes (list)
        (loop for i from 2 to 100 
            do ( setq isPrime t)
            (loop for j from 2 to i
                never (zerop (mod i j))
                    (setq isPrime f)
                    (break)
            )
        )
        (if (setq isPrime t)
            (append list i)
        )
        ) ;; <- end of defun
    ) ;; <- closes nothing
原始问题 编写一个函数,计算(可能是嵌套的)列表中质数的所有出现次数

即使作业中的问题是“写一个函数”,但并不是说你应该写一个可以同时计算所有东西的大函数。您可以编写一个这样大的函数,但如果您将问题分解为子问题,您将以不同的辅助函数结束,这些辅助函数:

  • 更容易理解(他们只做一件事)
  • 可以重用以构建其他函数
  • 子问题是,例如:如何确定一个数字是否是素数?如何在树上迭代(也称为嵌套列表)?如何计算 发生了什么

    基本思想是编写一个“is prime”函数,遍历树并对每个元素调用“is prime”;如果元素是素数且以前从未见过,请将1添加到计数器中,即函数的本地计数器

    您还可以展平输入树,以获取列表,然后对结果进行排序 列表您可以在跟踪最后一个列表的同时对列表进行迭代 所见值:如果该值与上一个值相同,则 已经知道这个数是否为素数;如果前面的数字不同,则 你必须先测试这个数字是否为素数

    您还可以进一步抽象一些内容,并定义一个高阶tree walker函数,该函数在树的每个叶子上调用一个函数。然后编写另一个“记忆”调用的高阶函数:它围绕 函数F,因此如果使用与前面相同的参数调用F, 它返回存储的结果,而不是重新计算

    例子 我将结合以上想法,因为如果你给老师这个答案,你可能必须仔细解释每个部分的作用(如果可以,对你来说很好);这不一定是“最佳”答案,但它涵盖了很多事情

    (defun tree-walk-leaves (tree function)
      (typecase tree
        (null nil)
        (cons
          (tree-walk-leaves (car tree) function)
          (tree-walk-leaves (cdr tree) function))
        (t (funcall function tree))))
    
    (defun flatten (tree &optional keep-order-p)
      (let ((flat nil))
        (tree-walk-leaves tree (lambda (leaf) (push leaf flat)))
        (if keep-order-p
            (nreverse flat)
            flat)))
    
    (defun prime-p (n)
      (or (= n 2)
          (and (> n 2)
               (oddp n)
               (loop
                  for d from 3 upto (isqrt n) by 2
                  never (zerop (mod n d))))))
    
    (defun count-occurences-of-prime (tree)
      (count-if #'prime-p (remove-duplicates (flatten tree))))
    
    (count-occurences-of-prime '(((1)(2))(5)(3)((8)3)))
    => 4
    
    相反,如果您不想删除重复项,而是要计算质数出现的次数,则可以执行以下操作:

    (count-if (memoize #'prime-p) (flatten tree))
    
    。。。其中
    memoize
    是:

    (defun memoize (function &key (test #'equalp) (key #'identity))
      (let ((hash (make-hash-table :test test)))
        (lambda (&rest args)
          (let ((args (funcall key args)))
            (multiple-value-bind (result exists-p) (gethash args hash)
              (values-list
               (if exists-p
                   result
                   (setf (gethash args hash)
                         (multiple-value-list (apply function args))))))))))
    

    (如果没有重复项,则备忘录无效)

    重要的是保持格式与语言的预期约定一致。它有助于阅读代码(尤其是与其他程序员一起阅读),并可以帮助您查看错误

    此外,您应该使用一个编辑器,它至少可以跟踪括号。在Emacs中,当您将光标放在第一个左括号中时,匹配的括号将亮显。你可以发现,你有一个额外的括号,没有任何用途

    (
    
    defun OccurencesOfPrimes (list)
            (loop for i from 2 to 100 
                do ( setq isPrime t)
                (loop for j from 2 to i
                    never (zerop (mod i j))
                        (setq isPrime f)
                        (break)
                )
            )
            (if (setq isPrime t)
                (append list i)
            )
            ) ;; <- end of defun
        ) ;; <- closes nothing
    
    原始问题 编写一个函数,计算(可能是嵌套的)列表中质数的所有出现次数

    即使作业中的问题是“写一个函数”,但并不是说你应该写一个可以同时计算所有东西的大函数。您可以编写一个这样大的函数,但如果您将问题分解为子问题,您将以不同的辅助函数结束,这些辅助函数:

  • 更容易理解(他们只做一件事)
  • 可以重用以构建其他函数
  • 子问题是,例如:如何确定一个数字是否是素数?如何在树上迭代(也称为嵌套列表)?如何计算 发生了什么

    基本思想是编写一个“is prime”函数,遍历树并对每个元素调用“is prime”;如果元素是素数且以前从未见过,请将1添加到计数器中,即函数的本地计数器

    您还可以展平输入树,以获取列表,然后对结果进行排序 列表您可以在跟踪最后一个列表的同时对列表进行迭代 所见值:如果该值与上一个值相同,则 已经知道这个数是否为素数;如果前面的数字不同,则 你必须先测试这个数字是否为素数

    您还可以进一步抽象一些内容,并定义一个高阶tree walker函数,该函数在树的每个叶子上调用一个函数。然后编写另一个“记忆”调用的高阶函数:它围绕 函数F,因此如果使用与前面相同的参数调用F, 它返回存储的结果,而不是重新计算

    例子 我将结合以上想法,因为如果你给老师这个答案,你可能必须仔细解释每个部分的作用(如果可以,对你来说很好);这不一定是“最佳”答案,但它涵盖了很多事情

    (defun tree-walk-leaves (tree function)
      (typecase tree
        (null nil)
        (cons
          (tree-walk-leaves (car tree) function)
          (tree-walk-leaves (cdr tree) function))
        (t (funcall function tree))))
    
    (defun flatten (tree &optional keep-order-p)
      (let ((flat nil))
        (tree-walk-leaves tree (lambda (leaf) (push leaf flat)))
        (if keep-order-p
            (nreverse flat)
            flat)))
    
    (defun prime-p (n)
      (or (= n 2)
          (and (> n 2)
               (oddp n)
               (loop
                  for d from 3 upto (isqrt n) by 2
                  never (zerop (mod n d))))))
    
    (defun count-occurences-of-prime (tree)
      (count-if #'prime-p (remove-duplicates (flatten tree))))
    
    (count-occurences-of-prime '(((1)(2))(5)(3)((8)3)))
    => 4
    
    相反,如果您不想删除重复项,而是要计算质数出现的次数,则可以执行以下操作:

    (count-if (memoize #'prime-p) (flatten tree))
    
    。。。其中
    memoize
    是:

    (defun memoize (function &key (test #'equalp) (key #'identity))
      (let ((hash (make-hash-table :test test)))
        (lambda (&rest args)
          (let ((args (funcall key args)))
            (multiple-value-bind (result exists-p) (gethash args hash)
              (values-list
               (if exists-p
                   result
                   (setf (gethash args hash)
                         (multiple-value-list (apply function args))))))))))
    

    (如果没有重复项,则memoize无效)

    isPrine是未定义的变量。循环缺少DO。BREAK调用调试器…您需要学习该语言的语法并首先做更简单的练习;尽量尊重语言的惯例,尤其是格式和缩进。循环也有一种特殊的语法。你可能已经读过那些页面了,但如果你没有读的话:(很多人提到