我想尝试扩展一些Lisp(Scheme,Racket,Clojure,any)来运行外部命令,如下所示:
;有(定义foo ……)(定义吧……);在命令(ls(foo bar)baz);这个lisp ……
Common Lisp有一个标准的错误系统,可用于实现它。
在Common Lisp实现中提供了一个 use-value 要么 store-value 重启类型错误 undefined-function 。
use-value
store-value
undefined-function
的 例 强>
CL-USER 69 > (flet ((call-use-value-restart (c) (use-value (lambda (arg) (format t "~%dummy function with arg ~a~%" arg)) c))) (handler-bind ((undefined-function #'call-use-value-restart)) (this-function-does-not-exist "foo"))) dummy function with arg foo NIL
在上面的例子中的功能 this-function-does-not-exist 不存在。如您所见,处理错误并调用另一个函数,然后执行一些输出。
this-function-does-not-exist
如果我们自己调用undefined函数,我们会收到一个错误:
CL-USER 70 > (this-function-does-not-exist "foo") Error: Undefined operator THIS-FUNCTION-DOES-NOT-EXIST in form (THIS-FUNCTION-DOES-NOT-EXIST "foo"). 1 (continue) Try invoking THIS-FUNCTION-DOES-NOT-EXIST again. 2 Return some values from the form (THIS-FUNCTION-DOES-NOT-EXIST "foo"). 3 Try invoking something other than THIS-FUNCTION-DOES-NOT-EXIST with the same arguments. 4 Set the symbol-function of THIS-FUNCTION-DOES-NOT-EXIST to another function. 5 Set the macro-function of THIS-FUNCTION-DOES-NOT-EXIST to another function. 6 (abort) Return to top loop level 0. Type :b for backtrace or :c <option number> to proceed. Type :bug-form "<subject>" for a bug report template or :? for other options. CL-USER 71 : 1 >
我们的示例基本上以编程方式调用重启号3:
它绑定一个调用该函数的处理程序 call-use-value-restart 当一个类型的错误 undefined-function 发生。
call-use-value-restart
功能 call-use-value-restart 然后打电话给 use-value 使用它提供的功能重启。在这里,您可以提供一个函数,该函数调用由其指定的名称的外部程序 (cell-error-name c) 。该 use-value 然后重启然后调用提供的函数并像往常一样继续执行程序。
(cell-error-name c)
的 提示解决方案 强>
通常,人们会编写一个小的顶级循环,其中提供了这样的处理程序。
的 另一种调用重启的方法 强>
在这个例子中我们使用a 钩 在发生错误时添加处理程序。这里我们使用全局变量 *debugger-hook* 。这应该是一个函数,在我们的例子中,它在条件时调用一个新函数 c 是类型的 undefined-function 。
*debugger-hook*
c
* (defun provide-a-function-hook (c hook) (declare (ignore hook)) (typecase c (undefined-function (use-value (lambda (arg) (format t "~%dummy function with arg ~a~%" arg)) c)))) PROVIDE-A-FUNCTION-HOOK * (setf *debugger-hook* #'provide-a-function-hook) #<FUNCTION PROVIDE-A-FUNCTION-HOOK> * (this-function-does-not-exist "foo") ; in: THIS-FUNCTION-DOES-NOT-EXIST "foo" ; (THIS-FUNCTION-DOES-NOT-EXIST "foo") ; ; caught STYLE-WARNING: ; undefined function: THIS-FUNCTION-DOES-NOT-EXIST ; ; compilation unit finished ; Undefined function: ; THIS-FUNCTION-DOES-NOT-EXIST ; caught 1 STYLE-WARNING condition dummy function with arg foo NIL
在球拍中你可以覆盖 #%top :
#%top
#lang racket (provide (combine-out (except-out (all-from-out racket) #%top) (rename-out [shell-curry #%top]))) (require racket/system) (define (stringify a) (~a (if (cmd? a) (cmd-name a) a))) (struct cmd (name proc) #:property prop:procedure (struct-field-index proc) #:transparent #:methods gen:custom-write [(define (write-proc x port mode) (display (string-append "#<cmd:" (stringify x) ">") port))]) (define (shell name) (define (cmd-proxy . args) (define cmd (string-join (map stringify (cons name args)) " ")) (system cmd)) cmd-proxy) (define-syntax shell-curry (syntax-rules () ((_ . id) (cmd 'id (shell 'id)))))
保存为shell.rkt并将此runner.rkt放在同一目录中:
#lang s-exp "shell.rkt" (define test (list /bin/ls /usr/bin/file)) (second test) ; ==> #<cmd:/usr/bin/file> (first test) ; ==> #<cmd:/bin/ls> ((second test) (first test)) ; ==> t (prints that /bin/ls is an executable on my system)
现在从这里开始吧 #lang myshell 或类似的东西很容易。
#lang myshell