Common lisp 使用宏运行函数

Common lisp 使用宏运行函数,common-lisp,Common Lisp,我的任务是使用macrodo primes计算a和b之间所有primes的列表,然后使用自定义代码打印它们 说(素数(n 5 15)(换行)(princ n))应打印以下4行: 五, 七, 十一, 十三, 这是我的密码: (defun is-prime (n &optional (d (- n 1))) (or (= d 1) (and (/= (rem n d) 0) (is-prime n (- d 1))))) (defun my-fun

我的任务是使用macrodo primes计算ab之间所有primes的列表,然后使用自定义代码打印它们

(素数(n 5 15)(换行)(princ n))应打印以下4行:

  • 五,
  • 七,
  • 十一,
  • 十三,
  • 这是我的密码:

    (defun is-prime (n &optional (d (- n 1))) 
      (or (= d 1)
          (and (/= (rem n d) 0)
               (is-prime  n (- d 1)))))
    
    (defun my-func (a b)
      (let (lst '())
        (loop for i from a to b do
          (if (is-prime i)
              (push i lst)
          )
        )
      (reverse lst))
    )
    
    (defmacro do-primes ((var startv endv) &body body)
      `(my-func ,startv ,endv) `(,@body)
    )
    
    (do-primes (n 5 15) (fresh-line) (princ n))
    
    但是,当我运行代码时,出现以下错误:

    EVAL:(FRESH-LINE)不是函数名;尝试改用符号


    如何使此代码正常工作,有什么想法吗?

    宏可能非常棘手。这就是为什么在调试它们时,首先要做的是对它们进行宏扩展。(在Emacs中有一个快捷方式:
    C-C RET
    )您还可以在REPL中键入
    (macroexpand[此处的宏用法])
    。在您的情况下,您应该键入:

     (macroexpand '(do-primes (n 5 15) (fresh-line) (princ n)))
    
    这将产生
    ((新鲜线)(原理N))


    由于
    (换行)
    不是函数名-
    换行
    是函数名,因此会出现该错误。

    宏可能非常棘手。这就是为什么在调试它们时,首先要做的是对它们进行宏扩展。(在Emacs中有一个快捷方式:
    C-C RET
    )您还可以在REPL中键入
    (macroexpand[此处的宏用法])
    。在您的情况下,您应该键入:

     (macroexpand '(do-primes (n 5 15) (fresh-line) (princ n)))
    
    这将产生
    ((新鲜线)(原理N))


    由于
    (换行)
    不是函数名-
    换行
    是函数名,因此会出现该错误。

    请记住:宏转换代码。

    如果你有这样的代码

    (do-primes (n 5 15)
     (fresh-line)
     (princ n))
    
    您应该问自己的第一个问题是:转换后的代码应该是什么样子?然后实际运行的代码

    一旦知道目标代码应该是什么样子,就可以编写翻译了

    Lisp有类似的宏:
    dolist
    dotimes
    。您可以检查它们的宏扩展。有几种方法可以实现上述功能。一种是对主体使用函数和闭包。通常情况下,在Lisp中,我希望它们能够扩展到一些低级代码中进行循环迭代

    在伪代码表示法中,更高级的编码方法是:

    for n from n below/upto 15
      when is-prime (n)
      do fresh-line () and princ (n)
    
    因此,
    do primes
    宏需要扩展为类似的代码-但Lisp代码。许多其他的方法也是可能的

    您的代码

    (defmacro do-primes ((var startv endv) &body body)
      `(my-func ,startv ,endv)
      `(,@body))
    
    宏有两个子窗体。为什么?第一个表单被计算,然后返回到nowhere。结果将被垃圾收集,因为它未被使用

    第二种形式

    `(,@body)`
    

    将进行计算,返回值将是返回的代码。这样说是没有道理的。括号不会对语句进行分组,也不会进行迭代。

    记住:宏转换代码。

    如果你有这样的代码

    (do-primes (n 5 15)
     (fresh-line)
     (princ n))
    
    您应该问自己的第一个问题是:转换后的代码应该是什么样子?然后实际运行的代码

    一旦知道目标代码应该是什么样子,就可以编写翻译了

    Lisp有类似的宏:
    dolist
    dotimes
    。您可以检查它们的宏扩展。有几种方法可以实现上述功能。一种是对主体使用函数和闭包。通常情况下,在Lisp中,我希望它们能够扩展到一些低级代码中进行循环迭代

    在伪代码表示法中,更高级的编码方法是:

    for n from n below/upto 15
      when is-prime (n)
      do fresh-line () and princ (n)
    
    因此,
    do primes
    宏需要扩展为类似的代码-但Lisp代码。许多其他的方法也是可能的

    您的代码

    (defmacro do-primes ((var startv endv) &body body)
      `(my-func ,startv ,endv)
      `(,@body))
    
    宏有两个子窗体。为什么?第一个表单被计算,然后返回到nowhere。结果将被垃圾收集,因为它未被使用

    第二种形式

    `(,@body)`
    

    将进行计算,返回值将是返回的代码。这样说是没有道理的。括号不会对语句进行分组,也没有迭代。

    您应该在此处检查示例:


    我想,它会解释你所需要的一切。

    你应该在这里检查示例:

    我想,它会解释你需要的一切