[racket-dev] Expansion of optional arguments in lambda
I think I figured out the actual answer which is semantics. If the
arguments are ever set!ed then my implementation will lead to a different
value.
(define (f a (b (begin (set! a 2) 3)))
a)
This should return 2 if b is not supplied, but in my expansion it would
return what ever was supplied for a.
On Sun, Feb 24, 2013 at 11:14 AM, Matthew Flatt <mflatt at cs.utah.edu> wrote:
> At Sun, 24 Feb 2013 09:51:12 -0800, Eric Dobson wrote:
> > lambda supports optional arguments, and does this by expanding out into a
> > core form that has flag arguments for if each argument is supplied. This
> is
> > tricky to type in TR and so I was investigating why it did it this way. I
> > did a micro benchmark on another method of expansion and it was 60%
> faster.
> > Is there a reason that racket does it the current way that I am missing.
> >
> > #lang racket
> >
> > (define f
> > (case-lambda
> > (() (f 1))
> > ((a) (f a (+ 3 a)))
> > ((a b) (f a b (* a b)))
> > ((a b c) (f a b c (- a (/ c b))))
> > ((a b c d) (+ a b c d))))
> >
> > (define (g (a 1) (b (+ 3 a)) (c (* a b)) (d (- a (/ c b))))
> > (+ a b c d))
>
> I'll have to investigate more, but I don't think the story is simple.
>
> Below are the decompiled forms, and you'll see that they're essentially
> the same, due to inlining and other compiler optimizations.
>
> Part of the answer is probably how the different forms interact with
> inlining in the timing loops. If I change the code to
>
> (define-values (f g)
> (let ()
> (define f ....)
> (define g ....)
> (values f g)))
>
> (set! f f)
> (set! g g)
>
> after the definition of `g', then performance is the same for the `f'
> and `g' (with a tiny difference that may be due to the order of clauses
> in `f' and `g').
>
> You may also want to look at performance in the case that the eventual
> body cannot be inlined (e.g., because it's too large). Then, I think the
> chain of applications for `f' will probably be significantly worse than
> the more direct implementation of `g'.
>
> ----------------------------------------
>
> (define-values
> (_f)
> (case-lambda
> (()
> '#(/private/tmp/c.rkt:5:4 #<path:/private/tmp/c.rkt> 5 4 44 10 #t)
> '(flags: preserves-marks single-result)
> '9)
> ((arg0-12)
> '#(/private/tmp/c.rkt:6:4 #<path:/private/tmp/c.rkt> 6 4 59 19 #t)
> '(flags: preserves-marks single-result)
> (let ((local13 (+ '3 arg0-12)))
> (let ((local16 (* arg0-12 local13)))
> (+ arg0-12 local13 local16 (- arg0-12 (/ local16 local13))))))
> ((arg0-27 arg1-28)
> '#(/private/tmp/c.rkt:7:4 #<path:/private/tmp/c.rkt> 7 4 83 23 #t)
> '(flags: preserves-marks single-result)
> (let ((local29 (* arg0-27 arg1-28)))
> (+ arg0-27 arg1-28 local29 (- arg0-27 (/ local29 arg1-28)))))
> ((arg0-40 arg1-41 arg2-42)
> '#(/private/tmp/c.rkt:8:4 #<path:/private/tmp/c.rkt> 8 4 111 33 #t)
> '(flags: preserves-marks single-result)
> (+ arg0-40 arg1-41 arg2-42 (- arg0-40 (/ arg2-42 arg1-41))))
> ((arg0-51 arg1-52 arg2-53 arg3-54)
> '#(/private/tmp/c.rkt:9:4 #<path:/private/tmp/c.rkt> 9 4 149 23 #t)
> '(flags: preserves-marks single-result)
> (+ arg0-51 arg1-52 arg2-53 arg3-54))))
>
> (define-values
> (_g)
> (case-lambda
> (() '(flags: preserves-marks single-result) '9)
> ((arg0-59 arg1-60 arg2-61 arg3-62)
> '(flags: preserves-marks single-result)
> (+ arg0-59 arg1-60 arg2-61 arg3-62))
> ((arg0-67 arg1-68 arg2-69)
> '(flags: preserves-marks single-result)
> (+ arg0-67 arg1-68 arg2-69 (- arg0-67 (/ arg2-69 arg1-68))))
> ((arg0-78 arg1-79)
> '(flags: preserves-marks single-result)
> (let ((local80 (* arg0-78 arg1-79)))
> (+ arg0-78 arg1-79 local80 (- arg0-78 (/ local80 arg1-79)))))
> ((arg0-91)
> '(flags: preserves-marks single-result)
> (let ((local92 (+ '3 arg0-91)))
> (let ((local95 (* arg0-91 local92)))
> (+ arg0-91 local92 local95 (- arg0-91 (/ local95
> local92)))))))))
>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.racket-lang.org/dev/archive/attachments/20130224/2fac8ad5/attachment-0001.html>