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