<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>