<div dir="ltr"><div>The closure trick is neat -- perhaps we can use it for docstrings, which is a commonly requested feature in Gerbil.</div><div><br></div><div>-- vyzo<br></div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Fri, Mar 27, 2020 at 2:29 PM Marc Feeley <<a href="mailto:feeley@iro.umontreal.ca">feeley@iro.umontreal.ca</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">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):<br>
<br>
<br>
(define info (make-table test: eq? weak-keys: #t))<br>
<br>
(define (inc x) (+ x 1))<br>
(define (squ x) (* x x))<br>
<br>
(table-set! info inc "increment function")<br>
(table-set! info squ "square function")<br>
<br>
(define (show proc)<br>
(pretty-print (list proc 'is (table-ref info proc "unknown"))))<br>
<br>
(show inc) ;; prints: (#<procedure #2 inc> is "increment function")<br>
(show squ) ;; prints: (#<procedure #3 squ> is "square function")<br>
(show car) ;; prints: (#<procedure #4 car> is "unknown")<br>
<br>
<br>
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:<br>
<br>
<br>
(define-type procinfo comment)<br>
<br>
(define (attach comment proc)<br>
(let ((@procinfo (make-procinfo comment)))<br>
(lambda args<br>
(##first-argument @procinfo) ;; keep @procinfo in the free vars<br>
(apply proc args))))<br>
<br>
(define (get-comment proc default)<br>
<br>
(define (extract x)<br>
(if (procinfo? x) (procinfo-comment x) default))<br>
<br>
(cond ((not (##closure? proc))<br>
default)<br>
((##interp-procedure? proc)<br>
(let ((rte (##interp-procedure-rte proc)))<br>
(extract (and (vector? rte)<br>
(= 2 (vector-length rte))<br>
(vector-ref rte 1)))))<br>
(else<br>
(extract (##closure-ref proc 1)))))<br>
<br>
(define dec (attach "decrement function" (lambda (x) (- x 1))))<br>
<br>
(pp (get-comment dec "unknown")) ;; prints: "decrement function"<br>
(pp (get-comment inc "unknown")) ;; prints: "unknown"<br>
(pp (get-comment car "unknown")) ;; prints: "unknown"<br>
<br>
<br>
Yet another way is to use the builtin ##decompile procedure (or the ##subprocedure-info primitive it calls):<br>
<br>
<br>
(declare (debug)) ;; keep source code in the compiled code<br>
<br>
(define (cube x) "this is the cube function" (expt x 3))<br>
<br>
(##decompile cube) ;; => (lambda (x) "this is the cube function" (expt x 3))<br>
<br>
<br>
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.<br>
<br>
Marc<br>
<br>
<br>
<br>
> On Mar 27, 2020, at 7:06 AM, Jörg F. Wittenberger <<a href="mailto:Joerg.Wittenberger@softeyes.net" target="_blank">Joerg.Wittenberger@softeyes.net</a>> wrote:<br>
> <br>
> Hi,<br>
> <br>
> A few questions regarding procedures:<br>
> <br>
> There are several classes of objects passing the `procedure?` predicate.<br>
> <br>
> - Is there a full list?<br>
> <br>
> - How expensive are those at startup initialization and call time?<br>
> (A rough ordering would do. Just to avoid expensive ones when there's<br>
> the option.)<br>
> <br>
> - I tend to use the following receipe to control the global exports<br>
> with gambit (currently nailed in practice to 0.9.2 for use with<br>
> lambdanative). Does imply any runtime overhead vs. no use of `let`<br>
> and resorting to gambits namespace facility?<br>
> <br>
> (define my-exported-proc #f)<br>
> <br>
> (let (...)<br>
> (define (my-private-proc ...) ...)<br>
> (define (my-to-be-exported ...) ...)<br>
> (set! my-exported-proc my-to-be-exported))<br>
> <br>
> - The real question of mine: How could I create additional runtime<br>
> predicates for procedures with minimal overhead? Any way to attach<br>
> tags to procedures? (Let's rule out the trivial solution to collect<br>
> procedures which should pass the predicate in a data structure and<br>
> look it up.)<br>
> <br>
> I need something where this fiction make sense (upper case be "dunno<br>
> how"):<br>
> <br>
> ;; ATTACH-TAG! is compiletime, maybe even only compiletime.<br>
> (define-macro (bless! proc tag) `(ATTACH-TAG! ,proc ',tag))<br>
> <br>
> (define (make-blessed tag)<br>
> (lambda (obj)<br>
> (and (procedure? obj) (eq? (GET-TAG obj) tag))))<br>
> <br>
> (define ispure? (make-blessed 'pure))<br>
> <br>
> (bless! + 'pure)<br>
> <br>
> ;;; at runtime:<br>
> <br>
> (ispure? +) ; => #t<br>
> (ispure? -) ; => #f ;; yeah, we forgot to bless is :-/<br>
> <br>
> <br>
> Thanks so much<br>
> <br>
> Jörg<br>
> <br>
> _______________________________________________<br>
> Gambit-list mailing list<br>
> <a href="mailto:Gambit-list@iro.umontreal.ca" target="_blank">Gambit-list@iro.umontreal.ca</a><br>
> <a href="https://mailman.iro.umontreal.ca/cgi-bin/mailman/listinfo/gambit-list" rel="noreferrer" target="_blank">https://mailman.iro.umontreal.ca/cgi-bin/mailman/listinfo/gambit-list</a><br>
<br>
<br>
_______________________________________________<br>
Gambit-list mailing list<br>
<a href="mailto:Gambit-list@iro.umontreal.ca" target="_blank">Gambit-list@iro.umontreal.ca</a><br>
<a href="https://mailman.iro.umontreal.ca/cgi-bin/mailman/listinfo/gambit-list" rel="noreferrer" target="_blank">https://mailman.iro.umontreal.ca/cgi-bin/mailman/listinfo/gambit-list</a><br>
</blockquote></div>