我认为没有任何解决方案define
可以便携或安全地工作,因为 Wrappeddefine
将构建本地绑定(正文中的前导形式)或非法(正文中的非前导形式),尽管我d 很高兴有一个计划标准的人指出我错在哪里。
相反,我认为像这种有点讨厌的黑客应该起作用。
(begin
(define inc undefined)
(define dec undefined)
(let ((x 3))
(set! inc (lambda (y)
(set! x (+ x y))
x))
(set! dec (lambda (y)
(set! x (- x y))
x))))
在这里,我依赖于一个名为的常量undefined
,这意味着“尚未正确定义”:Racket 提供了这个,racket/undefined
但它通常可以是任何东西:你可以在某个地方说
(define undefined 'undefined)
例如。
诀窍是使用占位符值在顶层定义您想要的东西,然后在let
.
我确定可以定义一个宏,它可以扩展为类似的东西(这就是为什么我将整个东西放在 a 中begin
):我没有这样做,因为它很繁琐,而且我使用 Racket 所以我不能轻易地写老式Lisp 宏在里面。
请注意,现代方案中显而易见的方法是使用define-values
:
(define-values (x y) (let (...) (values ...)))
做你想做的。如另一个答案中所述,define-values
如果您只有多个值,则可以将其实现为宏。但是,如果您根本没有多个值,那么您可以使用基于结果列表定义事物的东西:
(define-list (x y) (let (...) (list ...)))
这是该宏的两个粗略变体:第一个使用 Racket 的本机宏:
(require racket/undefined)
(define-syntax define-list
(syntax-rules ()
[(define-list () expr)
(let ((results expr))
(unless (zero? (length results))
(error "need an empty list"))
(void))]
[(define-list (name ...) expr)
(begin
(define name undefined)
...
(let ([results expr])
(unless (= (length results)
(length '(name ...)))
(error "wrong number of values"))
(set! name (begin0
(car results)
(set! results (cdr results))))
...))]))
而第二个在 Racket 中使用不卫生的宏:
(require compatibility/defmacro
racket/undefined)
(define-macro (define-list names expr)
`(begin
,@(let loop ([ntail names] [defs '()])
(if (null? ntail)
(reverse defs)
(loop (cdr ntail)
(cons `(define ,(car ntail) undefined) defs))))
(let ([results ,expr])
(unless (= (length results)
(length ',names))
(error "wrong number of values"))
,@(let loop ([ntail names] [i 0] [assignments '()])
(if (null? ntail)
(reverse assignments)
(loop (cdr ntail) (+ i 1)
(cons `(set! ,(car ntail) (list-ref results ,i))
assignments)))))))
请注意,这些都没有经过测试,我需要花一点时间说服自己第二个足够卫生。
但是有了这些:
> (define-list (inc dec)
(let ([i 0])
(list
(lambda ()
(set! i (+ i 1))
i)
(lambda ()
(set! i (- i 1))
i))))
> inc
#<procedure>
> (inc)
1
> (dec)
0
> (dec)
-1
>