Scheme 在公共lisp中模拟方案定义
我想知道如何在CommonLisp中模拟SchemeDefine,并想编写一个宏来模拟define。那么cl的defun deparameter defvar和scheme的define之间有什么不同,我如何做到这一点呢?虽然不清楚您为什么要这样做,但可以使用以下方法进行粗略的近似:Scheme 在公共lisp中模拟方案定义,scheme,lisp,common-lisp,Scheme,Lisp,Common Lisp,我想知道如何在CommonLisp中模拟SchemeDefine,并想编写一个宏来模拟define。那么cl的defun deparameter defvar和scheme的define之间有什么不同,我如何做到这一点呢?虽然不清楚您为什么要这样做,但可以使用以下方法进行粗略的近似: (defmacro define ((name &rest args) &body body) `(defun ,name ,args ,@body)) 然后,例如: (pprint
(defmacro define ((name &rest args) &body body)
`(defun ,name ,args
,@body))
然后,例如:
(pprint (macroexpand-1 '(define (xcons x y) (cons x y))))
; (DEFUN XCONS (X Y)
; (CONS X Y))
CL-USER> (pprint (macroexpand-1 '(define (list . args)
args)))
; (DEFUN LIST (&REST #:G1068)
; (LET ((ARGS #:G1068))
; ARGS))
这有两个问题
这不仅允许Scheme arglist。也就是说,它有点泄漏。如果您输入诸如&rest、&optional、&key或&aux之类的变量,而Common Lisp将专门处理这些变量,那么您将得到奇怪的行为。例如,如果您这样做:
(pprint (macroexpand-1 '(define (foo a &rest b)
(list a b))))
; (DEFUN FOO (A &REST B) (LIST A &REST B))
在Scheme中,这将是三个参数的函数,但在公共Lisp中,它是任意正非零个参数的函数
这不允许所有方案参数列表。特别是,它不处理虚线arglist,如中所示:
(define (list* x . xs)
(cons x xs))
要处理这些类型的情况,您需要更复杂的参数列表翻译。下面是一个返回通用Lisp函数可接受的新arglist的函数,它在函数体中重新启动原始Scheme arglist中变量的绑定:
(defun cl-arglist (scheme-arglist)
"Return a Common Lisp arglist corresponding to the Scheme
arglist, and a list of bindings (as for LET) that will
re-establish the variables declared in the original Scheme
arglist."
(labels ((convert (s-arglist cl-arglist bindings)
(cond
((atom s-arglist)
;; dotted arglists
(unless (null s-arglist)
(let ((cl-var (gensym)))
(setq cl-arglist (list* cl-var '&rest cl-arglist)
bindings (list* (list s-arglist cl-var) bindings))))
(values (nreverse cl-arglist)
(nreverse bindings)))
;; variable in arglist
(t
(let ((s-var (first s-arglist))
(cl-var (gensym)))
(convert (rest s-arglist)
(list* cl-var cl-arglist)
(list* (list s-var cl-var) bindings)))))))
(convert scheme-arglist '() '())))
(defmacro define ((name . arglist) . body)
(multiple-value-bind (arglist bindings) (cl-arglist arglist)
`(defun ,name ,arglist
(let ,bindings
,@body))))
例如:
(pprint (macroexpand-1 '(define (xcons x y) (cons x y))))
; (DEFUN XCONS (X Y)
; (CONS X Y))
CL-USER> (pprint (macroexpand-1 '(define (list . args)
args)))
; (DEFUN LIST (&REST #:G1068)
; (LET ((ARGS #:G1068))
; ARGS))
也就是说,要使Scheme代码在CommonLisp中运行而无需修改,您需要的不仅仅是这些。Scheme只有一个名称空间,而Common Lisp有多个名称空间。这意味着在Scheme中,您可以编写:
(let ((f (lambda (x y) (+ x y))))
(f 2 3))
;=> 5
在Common Lisp中,您必须编写:
(let ((f (lambda (x y) (+ x y))))
(funcall f 2 3))
;=> 5
我不确定是否有任何代码分析可以确定所有需要将F2 3转换为funcall F2 3的情况以及不需要的情况 虽然不清楚您为什么要这样做,但可以使用以下方法进行粗略近似:
(defmacro define ((name &rest args) &body body)
`(defun ,name ,args
,@body))
然后,例如:
(pprint (macroexpand-1 '(define (xcons x y) (cons x y))))
; (DEFUN XCONS (X Y)
; (CONS X Y))
CL-USER> (pprint (macroexpand-1 '(define (list . args)
args)))
; (DEFUN LIST (&REST #:G1068)
; (LET ((ARGS #:G1068))
; ARGS))
这有两个问题
这不仅允许Scheme arglist。也就是说,它有点泄漏。如果您输入诸如&rest、&optional、&key或&aux之类的变量,而Common Lisp将专门处理这些变量,那么您将得到奇怪的行为。例如,如果您这样做:
(pprint (macroexpand-1 '(define (foo a &rest b)
(list a b))))
; (DEFUN FOO (A &REST B) (LIST A &REST B))
在Scheme中,这将是三个参数的函数,但在公共Lisp中,它是任意正非零个参数的函数
这不允许所有方案参数列表。特别是,它不处理虚线arglist,如中所示:
(define (list* x . xs)
(cons x xs))
要处理这些类型的情况,您需要更复杂的参数列表翻译。下面是一个返回通用Lisp函数可接受的新arglist的函数,它在函数体中重新启动原始Scheme arglist中变量的绑定:
(defun cl-arglist (scheme-arglist)
"Return a Common Lisp arglist corresponding to the Scheme
arglist, and a list of bindings (as for LET) that will
re-establish the variables declared in the original Scheme
arglist."
(labels ((convert (s-arglist cl-arglist bindings)
(cond
((atom s-arglist)
;; dotted arglists
(unless (null s-arglist)
(let ((cl-var (gensym)))
(setq cl-arglist (list* cl-var '&rest cl-arglist)
bindings (list* (list s-arglist cl-var) bindings))))
(values (nreverse cl-arglist)
(nreverse bindings)))
;; variable in arglist
(t
(let ((s-var (first s-arglist))
(cl-var (gensym)))
(convert (rest s-arglist)
(list* cl-var cl-arglist)
(list* (list s-var cl-var) bindings)))))))
(convert scheme-arglist '() '())))
(defmacro define ((name . arglist) . body)
(multiple-value-bind (arglist bindings) (cl-arglist arglist)
`(defun ,name ,arglist
(let ,bindings
,@body))))
例如:
(pprint (macroexpand-1 '(define (xcons x y) (cons x y))))
; (DEFUN XCONS (X Y)
; (CONS X Y))
CL-USER> (pprint (macroexpand-1 '(define (list . args)
args)))
; (DEFUN LIST (&REST #:G1068)
; (LET ((ARGS #:G1068))
; ARGS))
也就是说,要使Scheme代码在CommonLisp中运行而无需修改,您需要的不仅仅是这些。Scheme只有一个名称空间,而Common Lisp有多个名称空间。这意味着在Scheme中,您可以编写:
(let ((f (lambda (x y) (+ x y))))
(f 2 3))
;=> 5
在Common Lisp中,您必须编写:
(let ((f (lambda (x y) (+ x y))))
(funcall f 2 3))
;=> 5
我不确定是否有任何代码分析可以确定所有需要将F2 3转换为funcall F2 3的情况以及不需要的情况 在通用Lisp中,在Scheme中定义不容易实现。它也不容易在Scheme中实现。它的转换在不同的范围内是不同的:
定义测试值;定义测试,值可以是任何值,甚至lambda。。这构成了一个过程对象
定义测试参数。。。身体定义程序测试
定义一些乐趣
定义测试。。。
定义Test2x。。。
...
是一种奇特的写作方式:
定义一些乐趣
letrec测试。。。
测试2λx。。。
...
那么,Common Lisp中的eqvivalent是什么:
定义myplus-otherfun;setf符号函数“myplus otherfun”
定义myplus lambda参数。身体定义myplus参数。身体
定义myplus。阿格斯。身体定义myplus参数。身体
定义值10;DEF参数值10
这是我对宏的看法。但这对内部定义不起作用:
defmacro定义名称或ll正文表达式(&M)
弗雷特点着休息
让我们最后一次
如果上次为null cdr
lst
追加最后一个lst
列出“最后一辆车”和“最后一辆休息cdr”
cond consp name或ll;定义乐趣a b。。。
`程序
defun,car name或ll,点到rest cdr name或ll,@expressions
defparameter,车名或ll',车名或ll
消费汽车用语;定义有趣的lambda a b。。。
eq caar表达式的lambda
`定义、命名或ll、@cadar表达式、@cddar表达式
t`let值,cons'程序表达式
当函数P值
setf符号函数',名称或ll值
defparameter、名称或ll值
定义过程lambda x*x
定义myproc proc
定义myplus'+
定义“测试”测试
定义testproc a b+a b
定义testproc2 lambda。b申请myplus a b
锂
st proc 10 myproc 10
myplus 2 3测试程序2 3
testproc2 1函数所有testproc2 1
测试;=>100 5 5 5测试
在公共Lisp中,在Scheme中定义不容易实现。它也不容易在Scheme中实现。它的转换在不同的范围内是不同的:
定义测试值;定义测试,值可以是任何值,甚至lambda。。这构成了一个过程对象
定义测试参数。。。身体定义程序测试
定义一些乐趣
定义测试。。。
定义Test2x。。。
...
是一种奇特的写作方式:
定义一些乐趣
letrec测试。。。
测试2λx。。。
...
那么,Common Lisp中的eqvivalent是什么:
定义myplus-otherfun;setf符号函数“myplus otherfun”
定义myplus lambda参数。身体定义myplus参数。身体
定义myplus。阿格斯。身体定义myplus参数。身体
定义值10;DEF参数值10
这是我对宏的看法。但这对内部定义不起作用:
defmacro定义名称或ll正文表达式(&M)
弗雷特点着休息
让我们最后一次
如果上次为null cdr
lst
追加最后一个lst
列出“最后一辆车”和“最后一辆休息cdr”
cond consp name或ll;定义乐趣a b。。。
`程序
defun,car name或ll,点到rest cdr name或ll,@expressions
defparameter,车名或ll',车名或ll
消费汽车用语;定义有趣的lambda a b。。。
eq caar表达式的lambda
`定义、命名或ll、@cadar表达式、@cddar表达式
t`let值,cons'程序表达式
当函数P值
setf符号函数',名称或ll值
defparameter、名称或ll值
定义过程lambda x*x
定义myproc proc
定义myplus'+
定义“测试”测试
定义testproc a b+a b
定义testproc2 lambda。b申请myplus a b
列表进程10 myproc 10
myplus 2 3测试程序2 3
testproc2 1函数所有testproc2 1
测试;=>100 5 5 5测试
你为什么要这么做?您尝试了什么?我想使用common lisp中的scheme代码,该代码与scheme代码一致。最大的问题是本地定义看起来与全局定义相同,但需要重写为标签。define可能是Scheme中最复杂的一种特殊形式,所以您实际上想用commonlisp编写一个Scheme解释器。看起来有点宽。哦,是的。我只是想知道是否有人用宏或其他东西来模拟CommonLisp中define的行为,所以我不需要手动更改代码。你为什么要这样做?您尝试了什么?我想使用common lisp中的scheme代码,该代码与scheme代码一致。最大的问题是本地定义看起来与全局定义相同,但需要重写为标签。define可能是Scheme中最复杂的一种特殊形式,所以您实际上想用commonlisp编写一个Scheme解释器。看起来有点宽。哦,是的。我只是想知道是否有人用宏或其他东西来模拟common lisp中define的行为,所以我不需要手动更改代码。必须将两个名称空间连接起来真的很麻烦。更糟糕的是,在lambdas中定义所有变量并将它们转换为标签。移植代码可能比生成宏更容易。@Sylvester完全同意。参数列表可能是最容易处理的事情之一。必须将两个名称空间连接起来,这真的很麻烦。更糟糕的是,在lambdas中定义所有变量并将它们转换为标签。移植代码可能比生成宏更容易。@Sylvester完全同意。参数列表可能是最容易处理的事情之一。是的,这就是我的想法。是的,这就是我的想法。