编写一个行为类似于 car、cadr、caddr 等的函数
Write a function that behaves like car, cadr, caddr etc
我是 lisp 的新手(我正在尝试使用 sbcl 和 ccl),我遇到了 car
和 cdr
的使用,它们可以在单个函数调用中任意链接,例如(caddr)
.
我在想如何编写这样的函数...
比如说,如果我像 (my-evaaal '(+ 2 1))
那样调用它,我想 my-eval
评估输入 s-exp 3 次
我已经用像这样的宏破解了我的方法
(my-ev $$$$ '(...)) 其中行为由第一个参数中 '$' 的数量决定,方法是将其转换为 char 序列 (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
然后,你可以有任意长的 eval 函数:
(handler-bind ((undefined-function #'multi-eval-handler))
(evaaaaaaaaaaaaaal '''''''''''''0))
现在,如果您编译代码,您将在编译时收到关于未知函数的警告,然后您可以消除警告。
我是 lisp 的新手(我正在尝试使用 sbcl 和 ccl),我遇到了 car
和 cdr
的使用,它们可以在单个函数调用中任意链接,例如(caddr)
.
我在想如何编写这样的函数...
比如说,如果我像 (my-evaaal '(+ 2 1))
my-eval
评估输入 s-exp 3 次
我已经用像这样的宏破解了我的方法
(my-ev $$$$ '(...)) 其中行为由第一个参数中 '$' 的数量决定,方法是将其转换为 char 序列 (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
然后,你可以有任意长的 eval 函数:
(handler-bind ((undefined-function #'multi-eval-handler))
(evaaaaaaaaaaaaaal '''''''''''''0))
现在,如果您编译代码,您将在编译时收到关于未知函数的警告,然后您可以消除警告。