【问题标题】:Write a function that behaves like car, cadr, caddr etc编写一个行为类似于 car、cadr、caddr 等的函数
【发布时间】:2019-04-09 12:15:13
【问题描述】:

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

我在想如何编写这样的函数...... 举例来说,如果我像 (my-evaaal '(+ 2 1)) 那样调用输入 s-exp,我希望 my-eval 对输入 s-exp 进行 3 次评估

我已经用类似的宏破解了我的方式 (my-ev $$$$ '(...)) 其中行为由第一个参数中“$”的数量决定...

基本需求:

;; 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

【问题讨论】:

    标签: common-lisp sbcl cdr


    【解决方案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 如此强大了!!
    • 这是一个很好的答案 - 我不知何故从未听说过 undefined-function 处理程序。
    猜你喜欢
    • 2011-09-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-10
    • 2022-06-19
    • 2015-11-29
    • 2016-07-28
    相关资源
    最近更新 更多