[racket] Use of map and eval to evaluate symbol in namespace

From: Matthew Flatt (mflatt at cs.utah.edu)
Date: Sun Aug 10 03:59:58 EDT 2014

I think you're looking for `keyword-apply`.

It's true that `eval` works as way to get reflective operations in
general, but it's better (again, for error checking and for efficiency)
when a language construct is accompanied with specific reflective
operations. In the case of keyword arguments, those operations include
`make-keyword-procedure`, `keyword-apply`, and
`procedure-reduce-keyword-arity`.

It's not always obvious which operations to include, and
`procedure-reduce-keyword-arity`, for one, wasn't included originally.
I think I might also have trouble defining "reflective operation"
precisely, as opposed to having constructs that support abstraction
more directly (such as allowing the superclass position of a `class`
form to be an expression). But if `keyword-apply` didn't exist, then
this example would make me think that some form of abstraction was
missing for keyword arguments, instead of seeming like a good use of
`eval`.

At Sat, 9 Aug 2014 10:10:08 -0400, Sean Kanaley wrote:
> There's a simple enough example I think: apply with keyword parameters.
> Apply has that built-in..sort of...but the list is supposed to be provided
> inline to APPLY, seemingly requiring apply to be applied (e.g. (apply apply
> (cons *thefunctiontoapply* params))), except keywords can't be expressions
> anyway. I have a bunch of card definitions for Dominion with many defaults:
> 
> (struct card (... actions buys ...))
> 
> (define (make-card ... #:actions actions #:buy buys ...)
>   ...)
> 
> The non-keyword-requiring way is
> 
> (define CARDS
>   (map (\ (lst) (apply make-card lst))
>           '([... 1 1 ...]
>            [... 2 0 ...])))
> 
> The keyword way is
> 
> ;ns is namespace
> (mapply (\ (lst) (eval `(apply make-card ',(car l) ,@(cdr l)) ns))
>         '([(...) #:actions 1 #:buys 1 ...]))
> 
> Short of making a big macro to take some exact format and get it to work
> with keywords and all that, eval seems to be just what is needed.
> 
> 
> On Sat, Aug 9, 2014 at 8:27 AM, Neil Van Dyke <neil at neilvandyke.org> wrote:
> 
> > Sounds like a good rule of thumb.  Two suggestions to add:
> >
> > * Maybe there could also be a second rule of thumb, like, "If you need
> > arbitrary Racket expressions, then consider whether you can do it with one
> > of the following patterns: [list some patterns involving combinations of
> > syntax extension, custom #lang, dynamic requires, considering whether
> > config files can actually be compile-time #lang, etc.]"  This is less
> > important than the first rule of thumb.
> >
> > * When we list typical newbie cases that don't actually require "eval", we
> > can expect that newbie will immediately want an example of the non-"eval"
> > way to do that typical thing.  At the very least, an example showing, say,
> > good use of hashes in parameters, with a sensible thin abstraction layer
> > over it, for that case.  These examples would be tedious to work through
> > and write up well, but someday some knowledgeable and benevolent person
> > will do it.  (I am not this person.  Book royalties aren't enough to ease
> > the pain. I'd rather that newbies just never heard of "eval" or were scared
> > away from it, rather than having to talk them down off the ledge all the
> > time.)
> >
> > Neil V.
> >
> >
> > Eli Barzilay wrote at 08/09/2014 07:31 AM:
> >
> >  I think that I ran into a nice way to discourage eval except when
> >> needed: the rule of thumb is to only use eval when you need to evaluate
> >> any arbitrary (Racket) expression.  It sounds simplistic but it covers
> >> lots of cases that make newbies run to eval:
> >>
> >> * I just want to get the value of a variable whose name is held in x
> >>
> >> * More common: I have a symbol/string that names a function, I just need
> >>    to call that function
> >>
> >> * I need to keep an update-able mapping from names to values, just like
> >>    what the toplevel does
> >>
> >> * I want to let people write an arithmetic expression instead of a
> >>    number
> >>
> >> In such cases questions like "do you need allow calling all functions",
> >> and "do you need to handle lambda expressions" have negative answers.
> >>
> >>
> >>
> >> On Sun, Jul 27, 2014 at 4:16 PM, Neil Van Dyke <neil at neilvandyke.org>
> >> wrote:
> >>
> >>> Maybe there should be a periodic public service announcement about not
> >>> using
> >>> "eval".  This time I will communicate in FAQ format:
> >>>
> >>> Q: How do I use eval?
> >>> A: Don't use eval.
> >>>
> >>> Q: But don't so many academic books feature eval prominently, so doesn't
> >>> that mean I should use try to eval?
> >>> A: Those books use eval for pedagogic reasons, or because the author is
> >>> enamored of some theoretical appeal of eval, or because the author wants
> >>> to
> >>> watch the world burn.  Don't use eval.
> >>>
> >>> Q: But, but, but, I am just starting to learn, and eval seems to do what
> >>> I
> >>> need.
> >>> A: Eval is almost certainly not what you want.  Learn how to use the
> >>> other
> >>> basics effectively.  Don't use eval.
> >>>
> >>> Q: I now am very comfortable with the language, I am aware that I should
> >>> avoid eval in almost all cases, and I can tell you why eval is actually
> >>> the
> >>> right thing in this highly unusual case.
> >>> A: Cool, that's why eval is there.
> >>>
> >>> Neil V.
> >>>
> >>>
> >>>
> > ____________________
> >  Racket Users list:
> >  http://lists.racket-lang.org/users
> >
> ____________________
>   Racket Users list:
>   http://lists.racket-lang.org/users

Posted on the users mailing list.