0

Let's call this function "dynamic-define".

Basically I want to write a macro or lambda that works like this:

$ (dynamic-define "variable" 123)
$ variable
$ => 123

I tried it:

(define-syntax dynamic-define
    (syntax-rules ()
      ((_ string <body>)
       (eval `(define ,(string->symbol string) <body>)))))

and it works as expected but doesn't seem to be a good solution.

I tried to use without eval like this:

(define-syntax dynamic-define                                           
    (syntax-rules ()                                                            
      ((_ string <body>)                                                        
       (define (string->symbol string) <body>))))

But when I try to use I get this error:

Error: invalid syntax (define (string->symbol "variable") 123)

What should I do?

(PLEASE: edit this question to fit native English and erase this line please)

Felipe
  • 16,649
  • 11
  • 68
  • 92

2 Answers2

2

You're running against a fundamental problem: you cannot do a real dynamic define in a "clean" way, hence your attempt using eval. Note that the two solutions above are both not dynamic -- all they give you is the ability to write "foo" instead of foo. As I said elsewhere, using eval is usually bad, and in this case it's worse since it's eval that is used from a macro which makes it very weird. This is in addition to having an implicit quasi-quote in your macro that makes things even more confusing. You could just as well define the whole thing as a plain function:

(define (dynamic-define string <body>)
  (eval `(define ,(string->symbol string) ,<body>)))

If you really need this to work, then it's best to take a step back and think about what it is that you need, exactly. On one hand, the above solutions are not dynamic since they require using the macro with a string syntax

(dynamic-define "foo" 123) ; instead of (define foo 123)

but how would it look to have a real dynamic definition that takes in a string? You'd probably expect this to define b:

(define a "b")
(dynamic-define a 123)

but this only becomes more confusing when you consider how it interacts with other bindings. For example:

(define y 123)
(define (foo s)
  (define x 456)
  (dynamic-define s 789)
  (+ x y))

Now, assuming that dynamic-define does what you want it to do, think about what you'd get with (foo "x") and (foo "y"). Worse, consider (foo "s") and (foo "+"). And even worse, what about

(foo (random-element '("x" "y" "s" "+" "define")))

? Clearly, if this dynamic-define really does some dynamic definition, then there is no sense that you can make of this code without knowing ahead of time what name foo will be called with. Without being able to make such sense, compilation goes out the window -- but much more importantly, correctness (or generally, the meaning of your code) dies.

In my experience, this kind of pattern is much better handled with hash tables and similar devices.

Eli Barzilay
  • 29,301
  • 3
  • 67
  • 110
  • Thank you Eli for the explanation. But what if I want to do something like SRFI 9? They didn't use anything like hashtables, define-macro or syntax-case. They just use the very common "syntax-rules". But after all I can use something like "make-". – Felipe May 05 '14 at 11:14
  • 2
    @FelipeMicaroniLalli: Well, something like defining new functions for a new data type is certainly possible, and very different from uses that can do with a hash table. However, they cannot be done with a plain `syntax-rules` if the macro needs to create new names. The thing is that in SRFI 9 you *don't* need to create new names -- that's the reason for specifying the accessor names in the new record definition, and in fact that's done intentionally, so it is possible to define it with simple `syntax-rules` macros. – Eli Barzilay May 05 '14 at 11:25
1

using define-macro

#> (define-macro (dynamic-define varstr val)
      `(define ,(string->symbol varstr) ,val))

#> (dynamic-define "variable" 123)
#> variable
123

using syntax-case

#> (define-syntax dynamic-define
     (lambda (stx)
       (syntax-case stx ()
         ((k varstr val)
          (with-syntax ([var (datum->syntax-object 
                              #'k
                              (string->symbol (syntax-object->datum #'varstr)))])
            #'(define var val))))))

#> (dynamic-define "variable" 123)
#> variable
123
C. K. Young
  • 219,335
  • 46
  • 382
  • 435
uselpa
  • 18,732
  • 2
  • 34
  • 52
  • 2
    SISC also supports `syntax-case` (and in fact, like pretty much every implementation with `syntax-case`, its `define-macro` is defined using `syntax-case`), so it's far more preferable to formulate procedural macros using `syntax-case`. In fact, pretty much _any_ system is better than `define-macro`. – C. K. Young Apr 26 '14 at 12:22
  • 1
    @ChrisJester-Young You're welcome to add your own answer based on your convictions. As far as I am concerned, hygienic macros is one of the things that Scheme got horribly wrong (and Common Lisp right). I also doubt that the alternative will be 1) more succinct and 2) "better" for any objective value of "better". Nevertheless I am open - surprise me! – uselpa Apr 26 '14 at 12:35
  • @ChrisJester-Young I've added a `syntax-case` version. I guess it confirms my point ;) – uselpa Apr 26 '14 at 22:03
  • It is more verbose in this case, yes. :-) (There are other cases where `syntax-case` macros are more concise, especially when dealing with complex destructuring.) I did edit your post to use the standard reader abbreviation for `syntax` (for implementations that have `quasisyntax`, `unsyntax`, and `unsyntax-splicing`, such as Racket, there are also similar abbreviations for those). – C. K. Young Apr 27 '14 at 03:07
  • Why syntax-case seems so hard? There are any material that I can learn this? Thanks. – Felipe Apr 27 '14 at 06:30
  • 1
    IMO `define-macro`, `syntax-rule` and `syntax-case` have their specific domains. For your question `syntax-case` is overkill. I love Greg Hendershott's "Fear of Macros", but since I haven't used SISC I don't know how much is applicable to it. Nevertheless a good read: http://www.greghendershott.com/fear-of-macros/ – uselpa Apr 27 '14 at 07:32
  • Didn't anyone notice that neither of these solutions is a good one since they're both not dynamic?? – Eli Barzilay May 03 '14 at 15:47
  • @EliBarzilay I don't see what you mean, can you please explain your point? – uselpa May 03 '14 at 15:56
  • 1
    @uselpa: all you get, with either version, is to write `(dyndef "foo" 1)` instead of `(def foo 1)`; the string must be there, literally, in the macro use -- and therefore it is no more dynamic than a regular define. See the explanation in my (non-)answer. – Eli Barzilay May 03 '14 at 16:07
  • I removed the "right answer" because as @Eli Barzilay it does not work to real dynamic values. I will wait for more solutions. No one could solve this so far. – Felipe May 16 '14 at 06:12
  • @FelipeMicaroniLalli I understand but I believe that this answer matches your question... you didn't ask what Eli suggests, and my understanding is that it's not even feasible. So at least you should reformulate your question. – uselpa May 16 '14 at 15:53
  • Hi @uselpa, I understand the example isn't so clear, but the name "dynamic" make it all clear that in place of the literal string I should be able to use a dynamic variable (otherwise this macro would be useless). I think it is feasible because SISC has a function/macro called (define-struct ...) http://sisc-scheme.org/manual/html/ch09.html#Records That do something similar. If the dynamic-define isn't possible, anyone could explain how define-struct works? Thank you! – Felipe May 18 '14 at 03:16