[racket-dev] Expansion of optional arguments in lambda

From: Robby Findler (robby at eecs.northwestern.edu)
Date: Sun Feb 24 15:12:37 EST 2013

Sounds like a good thing to add to test suite!

Robby


On Sun, Feb 24, 2013 at 2:04 PM, Eric Dobson <eric.n.dobson at gmail.com>wrote:

> 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)))))))))
>>
>>
>>
>
> _________________________
>   Racket Developers list:
>   http://lists.racket-lang.org/dev
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.racket-lang.org/dev/archive/attachments/20130224/24e38253/attachment.html>

Posted on the dev mailing list.