评估引用函数参数的代码
Evaluating code which refers to function parameters
更新:这个问题的原版没有完整描述我的情况的局限性。它现在包括一个示例,为了简单起见,还有一个可测试的最小示例。
我正在尝试将一段代码传递到程序中,以便稍后进行评估。具有所有约束的系统如下所示:
; External Library code - cannot be changed
(define (serialize-parameters . args)
(format some-file "~A~%" args))
(define (function-called-later-possibly-after-a-system-reboot callback)
(apply callback some-default-parameters (deserialize-parameters some-file)))
; Internal library code - can be changed, but the value of `code-snippet` cannot be hardcoded
(define (callback some-default-parameters code-snippet)
(eval code-snippet (current-module))
; Application code - can be changed, can be hardcoded
(define (main)
(serialize-parameters #:code-snippet '(format #t "~A~%" some-default-parameters)))
要点是允许应用程序在回调函数中执行任意代码片段。回调函数接收应用程序未知的其他参数,并且可能会在调用之间发生变化。
一个重要的约束是应用程序要发送给回调的参数被写入一个文件,然后在稍后的时间点(可能在系统重启后)读回。
此示例更易于测试,但未捕获所有约束:
(define (test foo bar)
(eval bar (current-module)))
(test "value of foo" '(format #t "~A~%" foo))
运行 这个程序的结果是 Unbound variable: foo
。我想要的是 test
函数的定义方式是调用的结果将 "value of foo\n" 打印到终端。这在 Guile 中可能吗?
谢谢。
这行不通。 eval
需要一个环境,你传递它 (current-module)
。这是模块中的顶级绑定,如 test
但不是任何词法绑定,如 foo
或 bar
。它们只是不存在于 (current-module)
返回的环境中。
你可以这样做:
(define foo "value of foo")
(eval '(format #t "~A~%" foo) (current-module))
; prints "value of foo"
; ==> #t
此外,房间里的大象是您可以使用 lambda 执行此操作:
(define (test value proc)
(proc value))
(test "value to process" (lambda (foo) (format #t "~A~%" foo)))
; prints "value to process"
; ==> #t
或者,但我猜你不能在回调中使用 format
,因为 "code-snippet" 可以有许多不同的值:
(define (main)
(serialize-parameters #:code-snippet "~A~%"))
(define (callback some-default-parameters code-snippet)
(format #t code-snippet some-default-parameters))
编辑
我认为你可以半硬编码:
(define (main)
(serialize-parameters #:code-snippet 'print-format))
(define (callback argument message)
(case message
((print-format) (format #t "~A~%" argument))
((other-message) (handle-message ...))
(else ...)))
您甚至可以将其设为动态调度程序。例如。你做这样的事情:
(define messages '())
(define (register-callback message proc)
(set! messages (cons (cons message proc) messages)))
(define (callback argument message)
(let ((found (assq message messages)))
(when found
((cdr found) argument))))
(register-callback 'print-format (lambda (arg) (format #t "~A~%" arg)))
(callback "test" 'print-format) ; prints "test"
现在只有消息存储在文件中,该文件很容易是任何数据文字。
更新:这个问题的原版没有完整描述我的情况的局限性。它现在包括一个示例,为了简单起见,还有一个可测试的最小示例。
我正在尝试将一段代码传递到程序中,以便稍后进行评估。具有所有约束的系统如下所示:
; External Library code - cannot be changed
(define (serialize-parameters . args)
(format some-file "~A~%" args))
(define (function-called-later-possibly-after-a-system-reboot callback)
(apply callback some-default-parameters (deserialize-parameters some-file)))
; Internal library code - can be changed, but the value of `code-snippet` cannot be hardcoded
(define (callback some-default-parameters code-snippet)
(eval code-snippet (current-module))
; Application code - can be changed, can be hardcoded
(define (main)
(serialize-parameters #:code-snippet '(format #t "~A~%" some-default-parameters)))
要点是允许应用程序在回调函数中执行任意代码片段。回调函数接收应用程序未知的其他参数,并且可能会在调用之间发生变化。
一个重要的约束是应用程序要发送给回调的参数被写入一个文件,然后在稍后的时间点(可能在系统重启后)读回。
此示例更易于测试,但未捕获所有约束:
(define (test foo bar)
(eval bar (current-module)))
(test "value of foo" '(format #t "~A~%" foo))
运行 这个程序的结果是 Unbound variable: foo
。我想要的是 test
函数的定义方式是调用的结果将 "value of foo\n" 打印到终端。这在 Guile 中可能吗?
谢谢。
这行不通。 eval
需要一个环境,你传递它 (current-module)
。这是模块中的顶级绑定,如 test
但不是任何词法绑定,如 foo
或 bar
。它们只是不存在于 (current-module)
返回的环境中。
你可以这样做:
(define foo "value of foo")
(eval '(format #t "~A~%" foo) (current-module))
; prints "value of foo"
; ==> #t
此外,房间里的大象是您可以使用 lambda 执行此操作:
(define (test value proc)
(proc value))
(test "value to process" (lambda (foo) (format #t "~A~%" foo)))
; prints "value to process"
; ==> #t
或者,但我猜你不能在回调中使用 format
,因为 "code-snippet" 可以有许多不同的值:
(define (main)
(serialize-parameters #:code-snippet "~A~%"))
(define (callback some-default-parameters code-snippet)
(format #t code-snippet some-default-parameters))
编辑
我认为你可以半硬编码:
(define (main)
(serialize-parameters #:code-snippet 'print-format))
(define (callback argument message)
(case message
((print-format) (format #t "~A~%" argument))
((other-message) (handle-message ...))
(else ...)))
您甚至可以将其设为动态调度程序。例如。你做这样的事情:
(define messages '())
(define (register-callback message proc)
(set! messages (cons (cons message proc) messages)))
(define (callback argument message)
(let ((found (assq message messages)))
(when found
((cdr found) argument))))
(register-callback 'print-format (lambda (arg) (format #t "~A~%" arg)))
(callback "test" 'print-format) ; prints "test"
现在只有消息存储在文件中,该文件很容易是任何数据文字。