Re: [racket-users] Narrow radix of string->number.

2017-01-01 Thread Robby Findler
I'm skeptical of an unbounded cache.

If we go by the sample from DrRacket's start up, then we don't really
need a cache to do better than the built-in number->string. Below is
some code that takes the version I had earlier with what I understood
to be Gustavo's suggestions and then just does better on the fixnums
between 0 and 9. I then changed the random inputs to sample from the
distribution that DrRacket demonstrated and you won't be surprised to
learn that this does better than having a cache. Below is the code.

I also tried to collect the arguments to number->string during
rebuilding all of the .zo files. Of the first 2.3 million calls about
99.5% of them were exact integers between 0 and 9 so probably this is
the only optimization we need to do. (My sampling method turned out to
be noisy, tho, but I don't think it affects the results.)

... unless someone comes up with some other benchmark or app we care about?

Robby

#lang racket
(require (for-syntax syntax/parse))

(define-syntax (mk-sample stx)
  (syntax-parse stx
[(_ (value:exact-nonnegative-integer
occurrences:exact-nonnegative-integer) ...)
 (define-values (cond-clauses count)
   (for/fold ([other-cases '()]
  [so-far 0])
 ([value (in-list (syntax->list #'(value ...)))]
  [occurrences (in-list (syntax->list #'(occurrences ...)))])
 (define next-count (+ so-far (syntax-e occurrences)))
 (values (cons #`[(< x #,next-count) #,value] other-cases)
 next-count)))
 #`(λ ()
 (define x (random #,count))
 (cond #,@(reverse cond-clauses)))]))

(define sample/drr
  (mk-sample
   (0 2399)
   (1 8116)
   (2 4278)
   (3 2196)
   (4 1346)
   (5 901)
   (6 364)
   (7 230)
   (8 106)
   (9 96)
   (10 42)
   (11 5)
   (12 3)
   (72 1)
   (100 34)
   (241 1)))

(define number->string**
  (let ([digits (list->vector (string->list "0123456789"))]
[cache (make-hasheqv)])
(λ (N)
  (hash-ref! cache N
 (λ ()
   (list->string
(let loop ([N N][acc empty])
  (define q (quotient N 10))
  (define next-acc (cons (vector-ref digits
(remainder N 10)) acc))
  (if (zero? q)
  next-acc
  (loop q next-acc)


(define (number->string* N)
  (cond [(and (exact-nonnegative-integer? N) (< N 10))
 (string (integer->char (+ (char->integer #\0) N)))]
[else
 (let* ([short-size 10]
[str (make-string short-size)])
   (let loop ([N N] [digits null] [i short-size])
 (cond
   [(zero? N)
(if (<= i 0)
(if (null? digits)
str
(string-append (apply string digits) str))
(substring str i short-size))]
   [else
(define q (quotient N 10))
(define r (remainder N 10))
(define d (integer->char (+ r (char->integer #\0
(cond
  [(<= i 0)
   (loop q (cons d digits) i)]
  [else
   (string-set! str (- i 1) d)
   (loop q '() (- i 1))])])))]))

(define-syntax-rule (test-it id ...)
  (begin
(module+ test
  (require rackunit)
  (check-equal? (id 1234567890987654321)
(number->string 1234567890987654321))
  (for ([x (in-range 1)])
(check-equal? (id x )
  (number->string x ...))

(test-it number->string**)
(test-it number->string*)

(define iterations 1)

(define-syntax-rule (time-it id ...)
  (begin
(define numbers (for/list ([i (in-range 1000)])
  (sample/drr)))
(begin
  (collect-garbage)
  (time
   (for* ([x (in-range iterations)]
  [n (in-list numbers)])
 (id n))
   (printf "~a " 'id))) ...))

(time-it number->string number->string* number->string**)

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: [racket-users] Errors in (Dr)Racket

2017-01-01 Thread Robby Findler
I mostly agree with Matthias, but wanted to add two things:

1) I've certainly experienced, many times, (both as the producer and
consumer (and sometimes simultaneously)) contracts that were added
because of runtime errors. But I do agree it is not as common as we
had hoped it would be. And Stephen's comments suggest that there is a
cultural issue here. So in that spirit, I want to say: please report
(as bugs!) code that raises errors down in its bowels instead of at
some more natural boundary in the code.

2) there is a technical difference between where the error is
discovered and where the contract goes and the error messages
generally have both of these components in them. It may be that the
error message text isn't clear and these two separate things are
getting conflated. (Overall, it is okay if the error is actually
discovered in the bowels and this information shows up in the stack
trace attached to the error message; the thing Matthias and I are
thinking about is whether or not there is a contract that lives at
some more reasonable boundary between the library you're using and the
code you wrote that uses it.)

Regardless, do post these errors. Feel free to ask if they seem to be
missing checks or if something else is going on and lets try to build
a better culture about getting good error messages!

Happy New Year. :)

Robby



On Sun, Jan 1, 2017 at 12:51 PM, Matthias Felleisen
 wrote:
>
>> On Jan 1, 2017, at 1:17 PM, Stephen De Gabrielle  
>> wrote:
>>
>> Hi All,
>>
>> I occasionally write code with errors* that cause the DrRacket error message 
>> to link to an internal Racket file, rather than my own incorrect code.
>>
>> The last time I did this it was doing web server code, but I've also managed 
>> it with GUI code.(and playing with DrRacket Plugins)
>>
>> I've not filed a report (or attempted a patch) on this before, mostly out of 
>> embarrassment, but also because because I feel out of my depth in the racket 
>> internals and the error was in my own code.
>>
>> Should I report these when I find them? Should I attempt to work out the 
>> cause and attempt a patch?
>
>
> A long time ago, Robby and I conjectured that if people reported those kinds 
> of errors, the creators of libraries would eventually protect their APIs with 
> contracts and the software would become more robust. This ‘gradual hardening’ 
> with contracts did not happen over time. Sure, some people added contracts to 
> libraries, others wrote them in Typed Racket. But all in all, we added 
> contracts because we wanted to not because of ‘client pressure.’
>
> Your email is validation that something was wrong with our conjecture, but I 
> can’t figure out what exactly is wrong. The word ‘fear’ and ‘embarrassment’ 
> are suggestive. Perhaps developers are intimidated by the creators APIs and 
> Libraries, because these people must be so much better and can’t possibly 
> make mistakes.
>
> Well we all make mistakes and if others report them, we get better at 
> overcoming these mistakes (starting with the elimination of bugs).
>
> Happy New Year — Matthias
>
> --
> You received this message because you are subscribed to the Google Groups 
> "Racket Users" group.
> To unsubscribe from this group and stop receiving emails from it, send an 
> email to racket-users+unsubscr...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: [racket-users] Errors in (Dr)Racket

2017-01-01 Thread Matthias Felleisen

> On Jan 1, 2017, at 1:17 PM, Stephen De Gabrielle  
> wrote:
> 
> Hi All,
> 
> I occasionally write code with errors* that cause the DrRacket error message 
> to link to an internal Racket file, rather than my own incorrect code. 
> 
> The last time I did this it was doing web server code, but I've also managed 
> it with GUI code.(and playing with DrRacket Plugins)
> 
> I've not filed a report (or attempted a patch) on this before, mostly out of 
> embarrassment, but also because because I feel out of my depth in the racket 
> internals and the error was in my own code. 
> 
> Should I report these when I find them? Should I attempt to work out the 
> cause and attempt a patch? 


A long time ago, Robby and I conjectured that if people reported those kinds of 
errors, the creators of libraries would eventually protect their APIs with 
contracts and the software would become more robust. This ‘gradual hardening’ 
with contracts did not happen over time. Sure, some people added contracts to 
libraries, others wrote them in Typed Racket. But all in all, we added 
contracts because we wanted to not because of ‘client pressure.’ 

Your email is validation that something was wrong with our conjecture, but I 
can’t figure out what exactly is wrong. The word ‘fear’ and ‘embarrassment’ are 
suggestive. Perhaps developers are intimidated by the creators APIs and 
Libraries, because these people must be so much better and can’t possibly make 
mistakes. 

Well we all make mistakes and if others report them, we get better at 
overcoming these mistakes (starting with the elimination of bugs). 

Happy New Year — Matthias

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


[racket-users] Errors in (Dr)Racket

2017-01-01 Thread Stephen De Gabrielle
Hi All,

I occasionally write code with errors* that cause the DrRacket error
message to link to an internal Racket file, rather than my own incorrect
code.

The last time I did this it was doing web server code, but I've also
managed it with GUI code.(and playing with DrRacket Plugins)

I've not filed a report (or attempted a patch) on this before, mostly out
of embarrassment, but also because because I feel out of my depth in the
racket internals and the error was in my own code.

Should I report these when I find them? Should I attempt to work out the
cause and attempt a patch?

Kind Regards (and Happy New Year)

Stephen

* who am I kidding? my code is *mostly* errors  :)
-- 
Kind regards,
Stephen
--
Bigger than Scheme, cooler than Clojure & more fun than CL.(n=1)
--

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: [racket-users] Narrow radix of string->number.

2017-01-01 Thread Matthew Butterick

> On Dec 31, 2016, at 12:05 PM, Robby Findler  
> wrote:
> 
> But this introduces an additional cost that's a little bit more
> troublesome to measure. Specifically, each namespace that instantiates
> `racket/base` will now take a tiny bit more space and take a tiny bit
> longer to initialize. 

> As one data point, here's a histogram of the 20k or so calls to
> number->string that happen during the start up of DrRacket (first
> entry in each list is the argument passed to number->string and the
> second is the number of times that call happened)

Hmm, well if the distribution of inputs is that imbalanced, perhaps this is the 
better cheat:

; 100,000 conversions of 100 random integers < 123
cpu time: 779 real time: 791 gc time: 16; number->string
cpu time: 769 real time: 771 gc time: 13; number->string**

; 100,000 conversions of 100 random integers < 123456
cpu time: 1365 real time: 1384 gc time: 22  ; number->string
cpu time: 941 real time: 955 gc time: 13; number->string**

; 100,000 conversions of 100 random integers < 123456789
cpu time: 1891 real time: 1904 gc time: 26  ; number->string
cpu time: 963 real time: 979 gc time: 17; number->string**


;
#lang racket

(define number->string**
  (let ([digits (list->vector (string->list "0123456789"))]
[cache (make-hasheqv)])
(λ (N)
  (hash-ref! cache N
 (λ ()
   (list->string
(let loop ([N N][acc empty])
  (define q (quotient N 10))
  (define next-acc (cons (vector-ref digits (remainder N 
10)) acc))
  (if (zero? q)
  next-acc
  (loop q next-acc)

(define-syntax-rule (test-it id ...)
  (begin
(module+ test
  (require rackunit)
  (check-equal? (id 1234567890987654321)
(number->string 1234567890987654321))
  (for ([x (in-range 1)])
   (check-equal? (id x )
 (number->string x ...))

(test-it number->string**)

(define iterations 10)

(define-syntax-rule (time-it number-to-convert id ...)
  (begin
(define numbers (for/list ([i (in-range 100)])
  (random number-to-convert)))
(begin
  (collect-garbage)
  (time
   (for* ([x (in-range iterations)]
  [n (in-list numbers)])
 (id n ...))

(time-it 123 number->string number->string**)
(time-it 123456 number->string number->string**)
(time-it 123456789 number->string number->string**)

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.