[gambit-list] How to distinguish procedures from procedures?
feeley at iro.umontreal.ca
Fri Mar 27 08:28:53 EDT 2020
The easiest solution that comes to mind is to use a weak eq? hash table to attach the information to the procedures (or any object):
(define info (make-table test: eq? weak-keys: #t))
(define (inc x) (+ x 1))
(define (squ x) (* x x))
(table-set! info inc "increment function")
(table-set! info squ "square function")
(define (show proc)
(pretty-print (list proc 'is (table-ref info proc "unknown"))))
(show inc) ;; prints: (#<procedure #2 inc> is "increment function")
(show squ) ;; prints: (#<procedure #3 squ> is "square function")
(show car) ;; prints: (#<procedure #4 car> is "unknown")
Another solution that is a bit hackish is to use a wrapper closure that stores the information in the closure’s free variables. The implementation is a bit more complicated because closures are represented differently by the compiler and interpreter:
(define-type procinfo comment)
(define (attach comment proc)
(let ((@procinfo (make-procinfo comment)))
(##first-argument @procinfo) ;; keep @procinfo in the free vars
(apply proc args))))
(define (get-comment proc default)
(define (extract x)
(if (procinfo? x) (procinfo-comment x) default))
(cond ((not (##closure? proc))
(let ((rte (##interp-procedure-rte proc)))
(extract (and (vector? rte)
(= 2 (vector-length rte))
(vector-ref rte 1)))))
(extract (##closure-ref proc 1)))))
(define dec (attach "decrement function" (lambda (x) (- x 1))))
(pp (get-comment dec "unknown")) ;; prints: "decrement function"
(pp (get-comment inc "unknown")) ;; prints: "unknown"
(pp (get-comment car "unknown")) ;; prints: "unknown"
Yet another way is to use the builtin ##decompile procedure (or the ##subprocedure-info primitive it calls):
(declare (debug)) ;; keep source code in the compiled code
(define (cube x) "this is the cube function" (expt x 3))
(##decompile cube) ;; => (lambda (x) "this is the cube function" (expt x 3))
The cell containing the procedure’s information (and accessed by ##subprocedure-info and ##subprocedure-parent-info) is embedded in the generated code and is read-only. Gambit would have to be extended to make it mutable.
> On Mar 27, 2020, at 7:06 AM, Jörg F. Wittenberger <Joerg.Wittenberger at softeyes.net> wrote:
> A few questions regarding procedures:
> There are several classes of objects passing the `procedure?` predicate.
> - Is there a full list?
> - How expensive are those at startup initialization and call time?
> (A rough ordering would do. Just to avoid expensive ones when there's
> the option.)
> - I tend to use the following receipe to control the global exports
> with gambit (currently nailed in practice to 0.9.2 for use with
> lambdanative). Does imply any runtime overhead vs. no use of `let`
> and resorting to gambits namespace facility?
> (define my-exported-proc #f)
> (let (...)
> (define (my-private-proc ...) ...)
> (define (my-to-be-exported ...) ...)
> (set! my-exported-proc my-to-be-exported))
> - The real question of mine: How could I create additional runtime
> predicates for procedures with minimal overhead? Any way to attach
> tags to procedures? (Let's rule out the trivial solution to collect
> procedures which should pass the predicate in a data structure and
> look it up.)
> I need something where this fiction make sense (upper case be "dunno
> ;; ATTACH-TAG! is compiletime, maybe even only compiletime.
> (define-macro (bless! proc tag) `(ATTACH-TAG! ,proc ',tag))
> (define (make-blessed tag)
> (lambda (obj)
> (and (procedure? obj) (eq? (GET-TAG obj) tag))))
> (define ispure? (make-blessed 'pure))
> (bless! + 'pure)
> ;;; at runtime:
> (ispure? +) ; => #t
> (ispure? -) ; => #f ;; yeah, we forgot to bless is :-/
> Thanks so much
> Gambit-list mailing list
> Gambit-list at iro.umontreal.ca
More information about the Gambit-list