[racket-dev] Expansion of optional arguments in lambda

From: Eric Dobson (eric.n.dobson at gmail.com)
Date: Sun Feb 24 15:04:21 EST 2013

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>

Posted on the dev mailing list.