[racket] Bouncing default value

From: Laurent (laurent.orseau at gmail.com)
Date: Sun Feb 12 05:48:31 EST 2012

Thank you all for your good and helpful answers.
Based on them, here is my current solution (without keywords), using macros
to ease the function definition:


#lang racket

(define default (gensym))
(define (default? x) (equal? x default))

(define-syntax parse-args-body
  (syntax-rules ()
    ; we found the optional arguments
    [(_ ((arg-opt val) ...) body ...)
     (let ([arg-opt (if (default? arg-opt) val arg-opt)]
           ...)
       body ...)]
    ; the first arg is not optional, parse the rest
    [(_ (arg1 arg2 ...) body ...)
     (parse-args-body (arg2 ...) body ...)]
    ; no optional arg found
    [(_ () body ...)
     (begin body ...)]
    ))

;; The (opt-arg val) are not turned into (opt-arg default)
;; because there is no real need to, and I tried and it was surprisingly
non-trivial (means: couldn't do it)
;; (because the parsing needs to be done *before* the define)
(define-syntax-rule (define/default (f arg ...) body ...)
  (define (f arg ...)
    (parse-args-body (arg ...) body ...)
    ))

;#| TESTS

(define/default (f arg1 [arg2 3])
  (list arg1 arg2))

(f 1) ; -> '(1 3)
(f 1 default) ; -> '(1 3)
(f 1 'smthg) ; -> '(1 smthg)

;|#

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.


Laurent



On Sat, Feb 11, 2012 at 22:31, Eli Barzilay <eli at barzilay.org> wrote:

> Four hours ago, Laurent wrote:
> >
> > (define (foo arg1 [arg2 <some-complicated-default-value>])
> >   ....)
> >
> > (define (bar [arg2 <the-same-complicated-default-value>])
> >   (foo 5 arg2))
>
> Robby's suggestion is basically:
>
>  (define (foo x [y #f])
>    (let ([y (or y <some-complicated-default-value>)])
>      ...))
>
>  (define (bar [y #f])
>    (foo 5 y))
>
> If #f is a valid value, the common way to deal with it is to have a
> special value instead:
>
>  (define none (gensym))
>
>  (define (foo x [y none])
>    (let ([y (if (eq? y none) <some-complicated-default-value> y)])
>      ...))
>
>  (define (bar [y none])
>    (foo 5 y))
>
> A different way to resolve this is to accept all arguments and pass
> them along:
>
>  (define (foo x [y <some-complicated-default-value>]) ...)
>
>  (define (bar . args) (apply foo 5 args))
>
> and this gets a bit more complicated if you want to do the same for
> keyworded functions too.
>
> Or to have a more precise arity:
>
>  (define bar
>    (case-lambda [()  (foo 5)]
>                 [(y) (foo 5 y)]))
>
> A variant of this is what Rodolfo wrote, which can use the same none
> value (useful if it's in a different module):
>
>  (define none (gensym))
>  (define (bar [y none])
>    (if (eq? y none) (foo 5) (foo 5 none)))
>
> --
>          ((lambda (x) (x x)) (lambda (x) (x x)))          Eli Barzilay:
>                    http://barzilay.org/                   Maze is Life!
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.racket-lang.org/users/archive/attachments/20120212/1ca6d21d/attachment-0001.html>

Posted on the users mailing list.