[racket] Call by Name

From: Joe Gilray (jgilray at gmail.com)
Date: Tue Nov 27 15:36:25 EST 2012

Thanks to all for the workable solutions.  I quickly implemented Ian's idea
and it is working for me... thanks again!

Here is a little background so you can better educate me:

As I've been learning Racket I've created a file called play.rkt that
contains useful code I've learned.  Its primary purpose is to allow me to
quickly search for techniques and code that I vaguely remember.  As I built
the file I created test functions alongside the code to make sure it is
working called test1 ... testn.  I originally used test-engine to run these
tests.  A nice feature of this setup was that I could use (test) to run all
the tests and (time (test)) to see how long they all took.  When submodules
came out I switched to rackunit (module+ test ...) and could run all the
tests simply by hitting the "run" button in DrRacket.  This worked fine but
I was just a little bothered that I could no longer see how long they all
take to run.

This morning I thought, "The test functions all look the same, there has to
be a way to call them all in a simple function that I can then run with
(time (call-fns))."  Ian's code does this for me
without having to add a thousand extra lines to the existing file.  Now I
hit "run" which checks that they are working, then type (time (call-fns))
if I want to see how long they take to run (without the return value
checking).  This is workable for me.  There are probably better ways and I
admit that this solution rested on a really bad naming convention
(test1...), but this is not production code, just a little something "on
the side" as it were.

Regards,
-Joe


On Tue, Nov 27, 2012 at 11:57 AM, Eli Barzilay <eli at barzilay.org> wrote:

> A few minutes ago, J. Ian Johnson wrote:
> > If you don't need to dispatch on name at runtime, you can write a
> > macro for this and use format-id to construct the identifier naming
> > the function. Otherwise you would need to use eval, which is highly
> > inadvisable.
>
> A few minutes ago, David Van Horn wrote:
> >
> > This is a slight variation on Ian's suggestion.  It uses a macro
> > (id-in name n m) that constructs a list consisting of the elements
> > namen ...  namem-1.
>
> These suggestions are not too useful, since they both basically
> provide an alternative syntax for something that is already in the
> code -- for example, the second one works only in cases like
> (id-in f 1 4) where you could just as well remove the space and use
> `f1'.  (Realizing how they're not useful is probably a good exercise
> in "getting" macors, or maybe also getting the difference between
> macros and `eval' (and fexprs...).)
>
> In any case, here's another thing to consider, which is more likely to
> be a good solution when you run into such a problem: build a table
> that maps names to functions:
>
>   (define function-names (make-hash))
>   (define (call-by-name name . args)
>     (apply (hash-ref function-names name) args))
>
> And when you define a function, add it to the table too:
>
>   (define (test1) 'foo)
>   (hash-set! function-names "test1" test1)
>   (define (test2) 'bar)
>   (hash-set! function-names "test2" test2)
>   (call-by-name (format "test~a" (add1 (random 2))))
>
> This is looks verbose -- but that's fixable with a very simple macro:
>
>   (define-syntax-rule (define/name (name . xs) body ...)
>     (begin (define (name . xs) body ...)
>            (hash-set! function-names (symbol->string 'name) name)))
>   (define/name (test1) 'foo)
>   (define/name (test2) 'bar)
>   (call-by-name (format "test~a" (add1 (random 2))))
>
>
> --
>           ((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/20121127/f6fe7975/attachment-0001.html>

Posted on the users mailing list.