使"define"评估其在Racket中的第一个参数



在LISP的某些方言中,SETSETQ之间有区别,第一个计算其第一个参数,因此需要使用(SET (QUOTE …) …)语法。

由于在Racket中,定义中不需要引用,因此define的行为与SETQ相同。是否存在行为类似SET的Racket函数?如果没有,如何写?

我尝试过(define (SET a b) (define (eval a) b) b),但当使用(provide SET)将其提供给其他语言时,它似乎不起作用。

下面是我对这个问题的快速尝试:

;; lib.rkt
#lang racket/base
(provide (rename-out [@set set]
[@#%top #%top]
[@set! set!]
[@define define]))
(require syntax/parse/define)
(define env (make-hash))
(define (set x v stx)
(unless (hash-has-key? env x)
(raise-syntax-error #f "undefined id" stx))
(hash-set! env x v))
(define-simple-macro (@#%top . x)
(hash-ref
env
'x
(λ () (raise-syntax-error #f "unbound id" (quote-syntax x)))))
(define (@set x v)
(set x v x))
(define-simple-macro (@set! x:id v)
(set 'x v (quote-syntax x)))
(define-simple-macro (@define x:id v)
(begin 
(when (hash-has-key? env 'x)
(raise-syntax-error #f "id already defined" (quote-syntax x)))
(hash-set! env 'x v)))
#lang racket/base
(require "lib.rkt")
(define x 1)
(set (if #t 'x 'y) 2)
(add1 x) ; 3
(set! x 3)
(add1 x) ; 4
(add1 y) ; y: unbound id in: y

请注意,这与原来的Racket在几个方面有所不同。例如:

  1. 未绑定的id现在在运行时而不是编译时报告
  2. set!现在无法与set!-transformer配合使用
  3. define不能用于定义函数
  4. define不能用于隐藏标识符

对于(2(和(3(,可以恢复原始行为,但我不希望答案太长,所以我没有包含完整的功能。现在,我不知道如何解决(4(。

还要注意,您只能通过define定义set标识符。如果要通过lambdalet等定义set标识符,还需要重新定义这些构造。

我会做得不那么冗长,也简单得多。

由于所有参数都是求值的,所以set或者说define%可以定义为一个函数!

(define (define% x y)
(eval `(define ,x ,y)))

当使用lambda使用旧式表单时,甚至可以使用define%定义函数。

(define 'ab (lambda (x y) (+ x y)))
(ab 3 5) ;; 7

它甚至在范围方面表现正确

(define (foo x)
(define% 'bar (lambda (x) (+ 1 x)))
(bar (bar (bar x))))
foo
;; #<procedure:foo>
bar
; bar: undefined;
;  cannot reference undefined identifier
; [,bt for context]
(foo 3)
6
;; after first call however, bar is available in global environment
;; as pointed out by @AlexKnauf
bar 
;; #<procedure:bar>

因此,存在一些范围界定问题。。。

(let ((x 0))                                                                                                                           
(define% 'counter (lambda () (set! x (+ x 1)) x)))                                                                        
counter
;; #<procedure>
(counter)
;; 1
(counter)
;; 2
(counter)
;; 3

最新更新