Racket功能的“智能”比较

时间:2017-01-18 22:34:34

标签: function compare racket

我有点异国情调。我需要比较函数,而不是它们的“起源”而不是“实例”。这就是我的意思:

(define-values (a b c d) (values #f #f #f #f))

(define (f x)
  (let ([g (λ (y) (printf "Please tell ~a this is ~a\n" x y))]
        [h (curry printf "Don't tell ~a this is ~a\n" x)])
    (if a
        (set! b g)
        (set! a g))
    (if c
        (set! d h)
        (set! c h))))

(f "me")
(f " me")

(a "possible")
(d "impossible")

(equal? a b) ; <====  Is it possible to compare these guys
(equal? c d) ; <====  to get #t in both cases?

在这两种情况下,我们得到两个不同的“实例”函数(即使捕获了不同的值),但两者都在源代码的相同位置声明。当然,获取这些函数正文的实际文本将解决问题,但是这里的其他答案告诉我在Racket中这是不可能的。是否有一些技巧可以帮助我?

修改: 这不是关于函数理论等价的问题。这完全是技术问题,而非Racket在编译代码中的函数表示。因此,它可以重新制定,例如,以下列方式:我可以从“用户”代码中获取某些例程的行号吗?我认为这应该是可行的,因为Racket调试器以某种方式获得它。

1 个答案:

答案 0 :(得分:1)

如果你控制了制作这些功能的代码,即使没有球拍内部的支持也可以完成。如果你保留一个表示特定lambda的计数器(或某个标识符),它可以在一个结构中包含不同的闭包,这个结构可以从宏扩展中具有相同的标识。这是一个演示:

#lang racket

;; makes a procedure object that can have other data connected to it
(struct proc (id obj) 
  #:property prop:procedure
  (struct-field-index obj)
  #:methods gen:custom-write
  [(define (write-proc x port mode)
     (display (format "#<procedure-id-~a>" (proc-id x)) port))])

;; compares the ids of two proc objects if they are proc objects
(define (proc-equal? a b)
  (and (proc? a)
       (proc? b)
       (= (proc-id a) (proc-id b))))

;; extends equal?, candidate to provide
(define (equal*? a b)
  (or (proc-equal? a b)
      (equal? a b)))

;; the state we keep
(begin-for-syntax
  (define unique-proc-id-per-code 0))

;; a macro that changes (lambda* ...) to 
;; (proc expansion-id (lambda ...)) 
(define-syntax (lambda* stx)
  (let ((proc-id unique-proc-id-per-code))
    (set! unique-proc-id-per-code (add1 unique-proc-id-per-code))
    #`(proc #,(datum->syntax stx proc-id) (lambda #,@(datum->syntax stx (cdr (syntax-e stx)))))))


;; test with making a counter
(define counter-from
  (lambda* (from)
    (lambda* ()
      (begin0
        from
        (set! from (add1 from))))))

;; evaluatin the outer shows it has id 0
counter-from ; ==> #<procedure-id-0>

;; make two counters that both use the inner lambda
(define from10 (counter-from 10))
(define from20 (counter-from 20))

;; both have the same expansion id
from10 ; ==> #<procedure-id-1>
from20 ; ==> #<procedure-id-1>

;; they are not equal?
(equal? from10 from20)      ; ==> #f (different object instances of proc)
;; but they are procedure-equal?
(proc-equal? from10 from20) ; ==> #t (same id, thus came from same macroexpansion)

免责声明:我更像是一个策划者,而不是一个敲诈者,所以这或许可以更优雅地完成,我不知道这将给予什么样的惩罚。