如何在方案中将列表转换为 code/lambda?
How to convert a list to code/lambda in scheme?
假设我有一个列表,例如:(define a '(+ (* p p) (* x x)))
.
如何使用 a
给出的表达式定义过程,例如:
(define (H x p) (+ (* p p) (* x x))))
?
我试图做类似的事情:(define (H x p) (eval a))
但它说 p
和 x
是未定义的。我想,apply
或类似的东西有一个简单的解决方法,但我无法理解它。
我想我可以根据传递给过程 H
的值修改列表中的 p
和 x
,然后计算新列表,但这有点难看...或者也许有一个很好的方法来做到这一点?
在 R5RS 方案中(在 Racket 中测试)以下工作:
#lang r5rs
(define foo
(eval (list 'lambda '(x p) '(+ (* p p) (* x x)))
(scheme-report-environment 5)))
然后,
(foo 3 4)
;=> 25
eval
is to use null-environment
的另一个选项,但 +
未定义。
球拍中的解决方案
您尝试做的实际上是将预定义的函数主体列表构造注入函数定义(宏)调用的主体。
(define expr '(+ (* p p) (* x x)))
(eval `(define (fun x p) ,expr))
如果你离开 (eval ...)
层,你会看到:
`(define (fun x p) ,expr)
;; '(define (fun x p) (+ (* p p) (* x x)))
代码,实际上是由eval
求值的。
由于此 eval
发生在全局环境级别,因此无需担心副作用。
下面是我使用 define-expr
宏的更复杂的解决方案。
他们解释说,为什么这么难解决。
毕竟,我看到实际上只需要一个 (eval `(define (<args>) ,expr)
结构,实际上不需要额外的宏。
球拍中的复杂解决方案
你也可以在 Racket 中做到这一点:
(define expr '(+ (* p p) (* x x)))
(define-syntax-rule (define-expr args expr)
(define args expr))
(eval `(define-expr (fun x p) ,expr))
这个调用在后台执行:
(define (fun x p) (+ (* p p) (* x x)))
您尝试做的实际上是一个动态宏。
这个问题是你必须给
运行时的函数体代码。
不知何故,您需要比宏的其余部分更多地通过一次评估来评估函数体表达式。
因此,有必要用
包装宏调用
(eval `<macrocall ,component-to-be-evaluated-once-more>)
我称这个构造为eval-over-macro-call
。
之后你可以调用定义的fun
函数:
(fun 3 4) ;; 25
普通口齿不清
个人比较喜欢common lisp的宏系统。更直接
(defparameter *expr* '(+ (* p p) (* x x)))
(defmacro defun-expr (fnname args expr)
`(defun ,fnname ,args ,expr))
(macroexpand-1 '(defun-expr fun (x p) *expr*)) ;; doesn't work
;; (DEFUN FUN (X P) *EXPR*) ;
;; T
;; you can see, that *EXPR* actually has to be evaluated once more
(macroexpand-1 `(defun-expr fun (x p) ,*expr*)) ;; this however is correct
;; (DEFUN FUN (X P) (+ (* P P) (* X X)))
;; Thus when you call the macro, you have to execute it using eval:
(eval `(defun-expr fun (x p) ,*expr*))
;; FUN ;; function is defined!
(fun 3 4) ;; 25
由于我对 Racket 的宏系统不是很熟悉,所以我使用伟大的 macroexpand-1
在 common lisp 中进行了宏构造,它显示了宏执行的代码构造。然后transferred/guessed对应Racket中的define-syntax-rule
.
在 Racket 中,macroexpand-1
是 (syntax->datum (expand-once '<macrocall>))
:
(syntax->datum (expand-once `(define-expr (fun x p) ,expr)))
;; '(define (fun x p) (+ (* p p) (* x x)))
假设我有一个列表,例如:(define a '(+ (* p p) (* x x)))
.
如何使用 a
给出的表达式定义过程,例如:
(define (H x p) (+ (* p p) (* x x))))
?
我试图做类似的事情:(define (H x p) (eval a))
但它说 p
和 x
是未定义的。我想,apply
或类似的东西有一个简单的解决方法,但我无法理解它。
我想我可以根据传递给过程 H
的值修改列表中的 p
和 x
,然后计算新列表,但这有点难看...或者也许有一个很好的方法来做到这一点?
在 R5RS 方案中(在 Racket 中测试)以下工作:
#lang r5rs
(define foo
(eval (list 'lambda '(x p) '(+ (* p p) (* x x)))
(scheme-report-environment 5)))
然后,
(foo 3 4)
;=> 25
eval
is to use null-environment
的另一个选项,但 +
未定义。
球拍中的解决方案
您尝试做的实际上是将预定义的函数主体列表构造注入函数定义(宏)调用的主体。
(define expr '(+ (* p p) (* x x)))
(eval `(define (fun x p) ,expr))
如果你离开 (eval ...)
层,你会看到:
`(define (fun x p) ,expr)
;; '(define (fun x p) (+ (* p p) (* x x)))
代码,实际上是由eval
求值的。
由于此 eval
发生在全局环境级别,因此无需担心副作用。
下面是我使用 define-expr
宏的更复杂的解决方案。
他们解释说,为什么这么难解决。
毕竟,我看到实际上只需要一个 (eval `(define (<args>) ,expr)
结构,实际上不需要额外的宏。
球拍中的复杂解决方案
你也可以在 Racket 中做到这一点:
(define expr '(+ (* p p) (* x x)))
(define-syntax-rule (define-expr args expr)
(define args expr))
(eval `(define-expr (fun x p) ,expr))
这个调用在后台执行:
(define (fun x p) (+ (* p p) (* x x)))
您尝试做的实际上是一个动态宏。 这个问题是你必须给 运行时的函数体代码。 不知何故,您需要比宏的其余部分更多地通过一次评估来评估函数体表达式。 因此,有必要用
包装宏调用(eval `<macrocall ,component-to-be-evaluated-once-more>)
我称这个构造为eval-over-macro-call
。
之后你可以调用定义的fun
函数:
(fun 3 4) ;; 25
普通口齿不清
个人比较喜欢common lisp的宏系统。更直接
(defparameter *expr* '(+ (* p p) (* x x)))
(defmacro defun-expr (fnname args expr)
`(defun ,fnname ,args ,expr))
(macroexpand-1 '(defun-expr fun (x p) *expr*)) ;; doesn't work
;; (DEFUN FUN (X P) *EXPR*) ;
;; T
;; you can see, that *EXPR* actually has to be evaluated once more
(macroexpand-1 `(defun-expr fun (x p) ,*expr*)) ;; this however is correct
;; (DEFUN FUN (X P) (+ (* P P) (* X X)))
;; Thus when you call the macro, you have to execute it using eval:
(eval `(defun-expr fun (x p) ,*expr*))
;; FUN ;; function is defined!
(fun 3 4) ;; 25
由于我对 Racket 的宏系统不是很熟悉,所以我使用伟大的 macroexpand-1
在 common lisp 中进行了宏构造,它显示了宏执行的代码构造。然后transferred/guessed对应Racket中的define-syntax-rule
.
在 Racket 中,macroexpand-1
是 (syntax->datum (expand-once '<macrocall>))
:
(syntax->datum (expand-once `(define-expr (fun x p) ,expr)))
;; '(define (fun x p) (+ (* p p) (* x x)))