Thank you all for your good and helpful answers.<div>Based on them, here is my current solution (without keywords), using macros to ease the function definition:</div><div><br></div><div><br></div><div><div>#lang racket</div>
<div><br></div><div>(define default (gensym))</div><div>(define (default? x) (equal? x default))</div><div><br></div><div>(define-syntax parse-args-body</div><div> (syntax-rules ()</div><div> ; we found the optional arguments</div>
<div> [(_ ((arg-opt val) ...) body ...)</div><div> (let ([arg-opt (if (default? arg-opt) val arg-opt)]</div><div> ...)</div><div> body ...)]</div><div> ; the first arg is not optional, parse the rest</div>
<div> [(_ (arg1 arg2 ...) body ...)</div><div> (parse-args-body (arg2 ...) body ...)]</div><div> ; no optional arg found</div><div> [(_ () body ...)</div><div> (begin body ...)]</div><div> ))</div><div>
<br></div><div>;; The (opt-arg val) are not turned into (opt-arg default) </div><div>;; because there is no real need to, and I tried and it was surprisingly non-trivial (means: couldn't do it)</div><div>;; (because the parsing needs to be done *before* the define)</div>
<div>(define-syntax-rule (define/default (f arg ...) body ...)</div><div> (define (f arg ...)</div><div> (parse-args-body (arg ...) body ...)</div><div> ))</div><div><br></div><div>;#| TESTS</div><div><br></div><div>
(define/default (f arg1 [arg2 3])</div><div> (list arg1 arg2))</div><div><br></div><div>(f 1) ; -> '(1 3)</div><div>(f 1 default) ; -> '(1 3)</div><div>(f 1 'smthg) ; -> '(1 smthg)</div><div><br>
</div><div>;|#</div></div><div><br></div><div>That'd be nice if all functions were implemented with something like that, so that the default symbol can be used without needing to know the actual value.</div><div><br>
</div>
<div><br></div><div>Laurent</div><div><br></div><div><br><br><div class="gmail_quote">On Sat, Feb 11, 2012 at 22:31, Eli Barzilay <span dir="ltr"><<a href="mailto:eli@barzilay.org">eli@barzilay.org</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">Four hours ago, Laurent wrote:<br>
><br>
> (define (foo arg1 [arg2 <some-complicated-default-value>])<br>
> ....)<br>
><br>
</div><div class="im">> (define (bar [arg2 <the-same-complicated-default-value>])<br>
> (foo 5 arg2))<br>
<br>
</div>Robby's suggestion is basically:<br>
<br>
(define (foo x [y #f])<br>
(let ([y (or y <some-complicated-default-value>)])<br>
...))<br>
<br>
(define (bar [y #f])<br>
(foo 5 y))<br>
<br>
If #f is a valid value, the common way to deal with it is to have a<br>
special value instead:<br>
<br>
(define none (gensym))<br>
<br>
(define (foo x [y none])<br>
(let ([y (if (eq? y none) <some-complicated-default-value> y)])<br>
...))<br>
<br>
(define (bar [y none])<br>
(foo 5 y))<br>
<br>
A different way to resolve this is to accept all arguments and pass<br>
them along:<br>
<br>
(define (foo x [y <some-complicated-default-value>]) ...)<br>
<br>
(define (bar . args) (apply foo 5 args))<br>
<br>
and this gets a bit more complicated if you want to do the same for<br>
keyworded functions too.<br>
<br>
Or to have a more precise arity:<br>
<br>
(define bar<br>
(case-lambda [() (foo 5)]<br>
[(y) (foo 5 y)]))<br>
<br>
A variant of this is what Rodolfo wrote, which can use the same none<br>
value (useful if it's in a different module):<br>
<br>
(define none (gensym))<br>
(define (bar [y none])<br>
(if (eq? y none) (foo 5) (foo 5 none)))<br>
<span class="HOEnZb"><font color="#888888"><br>
--<br>
((lambda (x) (x x)) (lambda (x) (x x))) Eli Barzilay:<br>
<a href="http://barzilay.org/" target="_blank">http://barzilay.org/</a> Maze is Life!<br>
</font></span></blockquote></div><br></div>