编写一个行为类似于 car、cadr、caddr 等的函数



我是Lisp的新手(我正在试验sbcl和ccl(,我遇到了carcdr的使用,它们可以像(caddr)一样在单个函数调用中任意链接。

我在徘徊如何编写行为这样的函数......例如,如果我像(my-evaaal '(+ 2 1))一样调用输入 s-exp my-eval我想评估输入 s-exp 3 次

我已经用像这样的宏破解了我的方式(my-ev $$$$ '(...其中行为由第一个参数中的"$"数字决定,将其转换为字符序列(coerce (symbol-name x) 'list)和评估和递归,直到列表为零......

基本需求:

;; if 
(defvar *foo* 1)
(eval '*foo*) ;; => 1
(eval ''*foo*) ;; => *foo*
(eval '''*foo*) ;; => '*foo*
;; then
(eval (eval (eval '''*foo*))) ;; => 1

所需语法

(my-eval '''*foo*) ;; => '*foo*
(my-evaal '''*foo*) ;; => *foo*
(my-evaaal '''foo) ;; => 1

像CAAR,CADR这样的函数只是常规函数;如果你愿意,你可以定义一个宏来帮助你轻松定义它们。

 (defpackage :so (:use :cl :ppcre))
 (in-package :so)
 (defmacro eval%% (count form)
   (case count
     (0  form)
     (1 `(eval ,form))
     (t (check-type count (integer 2))
        `(eval%% ,(1- count) (eval ,form)))))

例如,以下内容:

(eval%% 3 '''most-positive-fixnum)

依次扩展为:

(EVAL%% 2 (EVAL '''MOST-POSITIVE-FIXNUM))
(EVAL%% 1 (EVAL (EVAL '''MOST-POSITIVE-FIXNUM)))
(EVAL (EVAL (EVAL '''MOST-POSITIVE-FIXNUM)))

然后,您可以按如下方式定义自定义 eval 函数,甚至可以使用另一个宏:

(defun evaal (x) (eval%% 2 x))
(defun evaaal (x) (eval%% 3 x))

处理程序和重新启动

或者,请注意,您可以捕获对未定义函数的调用:

(block nil
  (handler-bind ((undefined-function
                  (lambda (e)
                    (return
                      (values (cell-error-name e)
                              (compute-restarts e))))))
    (evaaaaaal 'a)))
=> EVAAAAAAL
  (#<RESTART CONTINUE {7FD5F5F8CE43}> #<RESTART USE-VALUE {7FD5F5F8CE03}>
   #<RESTART SB-KERNEL::RETURN-VALUE {7FD5F5F8CDC3}>
   #<RESTART SB-KERNEL::RETURN-NOTHING {7FD5F5F8CD83}>
   #<RESTART SWANK::RETRY {7FD5F5F8DA13}> #<RESTART ABORT {7FD5F5F8DEC3}>
   #<RESTART ABORT {7FD5F5F8EB03}>)

您还可以使用标准的 USE-VALUE 重新启动来提供要调用的不同函数:

(defun multi-eval-handler (condition)
  (let ((name (cell-error-name condition)))
    (when (eq (symbol-package name) (find-package :so))
      (register-groups-bind ((#'length count)) ("EV(A+)L" (string name))
        (invoke-restart 'use-value (make-repeated-evaluator count))))))

您需要一个辅助函数来计算 N 次评估:

(defun make-repeated-evaluator (count)
  (case count
    (0 #'identity)
    (1 #'eval)
    (t (check-type count (integer 2))
       (lambda (form)
         (loop
            for value = form then (eval value)
            repeat count
            finally (return value))))))

例如:

(funcall (make-repeated-evaluator 3)
         '''most-positive-fixnum)
=> 4611686018427387903

然后,你可以有任意长的评估函数:

 (handler-bind ((undefined-function #'multi-eval-handler))
     (evaaaaaaaaaaaaaal '''''''''''''0))

现在,如果你编译代码,你会在编译时收到关于未知函数的警告,那时你可以屏蔽警告。

最新更新