I've extracted a piece of a language implementation here (also attached)
  https://gist.github.com/wilbowma/87d7e18718e08968cc4b2d003efbff2b

It provides two implementations of a little language that provides an unbounded
number of implicit global mutable variables.
I decided to bind the first 1000 of them because I figure no user would generate
that many, instead of doing anything clever.

One method uses `let-syntax` and implements these variables with set!
transformers, and the other just binds the variables with `let`.

It seems the version that uses `let-syntax` runs in time directly proportional
to the number of these variables I decide to bind, i.e., the number of macros I
introduce via `let-syntax`; about 1ms per variable bound, regardless of whether
the macros are ever used.

This behaviour surprised me a lot. Is this expected? 

-- 
William J. Bowman

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/racket-dev/YirU6gt5MxSnLcvf%40williamjbowman.com.
#lang racket
(require (for-syntax racket/syntax))

#|
1,000 fvars; let-syntax implementation
cpu time: 1162 real time: 1165 gc time: 156

10,000 fvars; let-syntax implementation
cpu time: 10928 real time: 10964 gc time: 1374

1,000 fvars; let implementation
cpu time: 20 real time: 20 gc time: 3

10,000 fvars; let implementation
cpu time: 225 real time: 225 gc time: 54
|#

(begin-for-syntax
  (define current-fvars (make-parameter 10000))

  (define (bind-fvars s n tail)
    #`(let-syntax
          #,(for/list ([i (in-range 0 n)])
              (with-syntax ([fvar (syntax-local-introduce (format-id #f "fv~a" 
i))]
                            [offset i]
                            [stack s])
                #`[fvar (make-set!-transformer
                         (lambda (stx)
                           (syntax-case stx ()
                             [(set! id v)
                              #`(vector-set! stack offset v)]
                             [id (identifier? #'id)
                                 #`(vector-ref stack offset)])))]))
        #,tail)))

(define-syntax (my-module stx)
  (syntax-case stx ()
    [(_ e ...)
     (with-syntax ([s #'stack])
       #`(let ([s (make-vector #,(current-fvars) (void))])
           #,(bind-fvars #'s (current-fvars) #`(begin e ...))))]))

(define-namespace-anchor a)

(displayln "1,000 fvars; let-syntax implementation")

(time
 (eval
  '(begin
     (begin-for-syntax
       (current-fvars 1000))
     (my-module
      (set! fv0 8)
      (set! fv1 8)
      (+ fv0 fv1)))
  (namespace-anchor->namespace a)))

(displayln "10,000 fvars; let-syntax implementation")

(time
 (eval
  '(begin
     (begin-for-syntax
       (current-fvars 10000))
     (my-module
      (set! fv0 8)
      (set! fv1 8)
      (+ fv0 fv1)))
  (namespace-anchor->namespace a)))

(define-for-syntax (bind-fvars2 n tail)
  #`(let #,(for/list ([i (in-range 0 n)])
             (with-syntax ([fvar (syntax-local-introduce (format-id #f "fv~a" 
i))])
               #`[fvar (void)]))
      #,tail))

(define-syntax (my-module2 stx)
  (syntax-case stx ()
    [(_ e ...)
     (bind-fvars2 (current-fvars) #`(begin e ...))]))

;; expansion time increases with the number of let bindings, but not nearly as 
bad
;; expansion time seems to be 1ms per fvar, i.e., per let-syntax?

(displayln "1,000 fvars; let implementation")

(time
 (eval
  '(begin
     (begin-for-syntax
       (current-fvars 1000))
     (my-module2
      (set! fv0 8)
      (set! fv1 8)
      (+ fv0 fv1)))
  (namespace-anchor->namespace a)))

(displayln "10,000 fvars; let implementation")
(time
 (eval
  '(begin
     (begin-for-syntax
       (current-fvars 10000))
     (my-module2
      (set! fv0 8)
      (set! fv1 8)
      (+ fv0 fv1)))
  (namespace-anchor->namespace a)))

Reply via email to