在lisp / scheme中,除了lambda / closures外,WRITE和READ函数可以用该语言输出任何数据,然后将其读回。
我想做的一个例子是:
(define f (lambda (x) (lambda (y) (+ x y))))
(write (f 2))
应该输出一些可以读回并像这样使用的东西
((read) 7)
获得结果9
。
这将如何实施?是否有任何教科书或文档说明使用此功能进行口译的详细信息?谢谢
答案 0 :(得分:0)
实际上Lisp系统不能读写任意对象:只有足够简单的对象。以Common Lisp为例,给出
(defclass foo ()
((x :reader foo-x :initarg :x)))
然后:
> (make-instance 'foo :x 2)
#<foo 40200A9813>
那是无法阅读的东西。
要使Lisp / Scheme能够将常规对象写入(在下面“隐藏”)到文件中,并从文件中读取(在“ unstash”以下)它们,至少需要足够的自省才能知道哪些部分的对象。为了能够可靠地存储和取消存储对象,您还需要能够知道对象所依赖的对象。对于任何函数或闭包都不存在任何可移植的方式,而且依赖问题很严重。
作为一个例子,考虑一下(现在在Scheme中):
(define y 3)
(define (bar x)
(+ x y))
(define (foo x)
(cons (bar x) x))
如果我说(stash foo "/tmp/foo")
应该怎么办?
foo
,以便以某种形式存储它,以便在加载时可以对其进行重构。foo
有依赖关系:它依赖于bar
和bar
依次依赖于y
,也依赖于cons
和{{1 }}可能可以忽略(但仅可能)。我还需要藏起来那些东西吗?因为如果我不尝试从存放的文件中撤回定义,如果我在没有定义的上下文中执行该操作,将导致严重失败。因此,将通用对象(尤其是功能)存储到外部存储中并正确执行是一个巨大的问题。特别是,我认为这甚至不是一个定义明确的问题。例如,在许多实现中,诸如+
或+
之类的东西实际上可能并不代表您所假设的内容,而诸如函数应用程序之类的隐式操作可能不符合您的想法:应该 that 与要保存的对象一起保存吗?
正确地 和一般地解决这些问题非常困难,实际上,这些问题的处境还不够好,甚至没有明确的解决方案。>
但是,这并不意味着该问题在某些情况下是无法解决的,因为您根本不关心其中的某些或全部问题。
这是Racket中的一些代码,例如一些简单的案例。
注释:
cons
等同于调用load
并具有所有危险; eval
的定义可能错过了define/stashing
语法中的一些重要情况; define
只能在顶层使用(因为根本没有处理词法环境),否则将无法正常工作; 总的来说,这只是一个骇人听闻的演示,它很容易处理一些在实践中可能很有趣的特殊情况。
define/stashing
要使用此功能,您需要使用(define definition-map (make-hasheqv))
(define (save-definition! thing source-form)
(hash-set! definition-map thing source-form)
thing)
(define (get-definition thing)
(hash-ref definition-map thing))
(define (clear-definitions!)
(hash-clear! definition-map))
(define-syntax define/stashing
;; This is probably missing cases
(syntax-rules ()
[(_ (name) form ...)
(define name (save-definition! (lambda () form ...)
'(lambda () form ...)))]
[(_ (name arg ...) form ...)
(define name (save-definition!
(lambda (arg ...) form ...)
'(lambda (arg ...) form ...)))]
[(_ (name arg ... . rest) form ...)
(define name (save-definition!
(lambda (arg ... . rest) form ...)
'(lambda (arg ... . rest) form ...)))]
[(_ name value)
(define name (save-definition! value 'value))]))
(define (stash thing file)
(call-with-output-file
file
(λ (o)
(write (get-definition thing) o)
thing)
#:mode 'text
#:exists 'truncate/replace))
(define (unstash file)
(load file))
而不是define/stashing
(模块可以使define
成为 define
),然后define/stashing
和stash
:
unstash
如果要隐藏递归函数,则需要使用本地定义编写它们:
> (define/stashing (cons-1 x) (cons x 1))
> (stash cons-1 "/tmp/x")
#<procedure>
> (cons-1 2)
'(2 . 1)
> ((unstash "/tmp/x") 2)
'(2 . 1)
将起作用,而
(define/stashing (fact n)
(let floop ([m 1] [t 1])
(if (= m n)
(* t m)
(floop (+ m 1) (* t m)))))
不会,但是如果您将其(define/stashing (fact n)
(if (= n 1)
n
(* n (fact (- n 1)))))
插入定义的相同REPL中,它会出现。