开发者

how to create dynamic list of symbols and commands in scheme without using eval-string?

I am trying to make a function call using the data I read from an input file. I have the following function that takes a list of vertices and an arbitrary numbers of commands. (I simplified the function a bit here).

(create-graph vertex-list cmd0 cmd1 ... cmdn)

My input file would have something like:

(2
(vertex-create "Paris")
(vertex-create "London"))

where 2 is the the number of vertices.

With that input, I would like to call create-graph as

(create-graph
  '(v1 v2)
  (set! v1 (vertex-create "Paris"))
  (set! v2 (vertex-create "London"))
)

where v1 and v2 are symbols created for each vertex.

What I have now is to construct the whole function as a string and use eval-string. But is there a way to make that function call without using eval-string? Using eval for some parts should be fine. More specifically, I think I need to be able to do these dynamically:

I would appreciate your input. Thanks!


Yes, you can do this without eval. Yes, that's a much better idea. It's important to understand that every program can be seen as an interpreter for its inputs, but once you understand eval, you should never use it again....

Your program might wind up looking something like this:

#lang racket

(define cmds (file->value input-file))

(define vertex-names (for ([i (in-range (length cmds))])
                       (string->symbol (format "v~s" i))))

(create-graph
 (for/list ([v (in-list vertex-names)]
            [cmd (in-list cmds)])
   (list
    v
    (match cmd
      [(list 'vertex-create str) (vertex-create str)]
      ... other choices? ...
      ))))

I assumed that rather than specifying the number of vertices, that you'd just infer it from the length of the list of commands. Also, I can't see what other "commands" there might be. Also, your set!s are unnecessary and yucky :).


A macro that an be used to create such a list:

(define-syntax make-create-graph-call
  (syntax-rules ()
    ((_ symbol-count commands) 
     (let* ((sym-list (create-sym-list symbol-count))
            (cmds (let loop ((slist sym-list) 
                             (cms commands)
                             (res '()))
                    (if (not (null? slist))
                        (loop (cdr slist) (cdr cms)
                              (cons `(set! ,(car slist) ,(car cms)) res))
                        (reverse res)))))
       `(create-graph ',sym-list ,@cmds))))) 

Where create-sym-list is defined as:

(define (create-sym-list count)
  (let loop ((c 0) (res '()))
    (if (< c count)
        (loop (+ 1 c) (cons (string->symbol 
                             (string-append "v" (number->string (+ 1 c)))) res))
        (reverse res))))

Usage:

(make-create-graph-call 2 '((vertex-create "Paris") (vertex-create "London")))

=> (create-graph '(v1 v2) (set! v1 (vertex-create "Paris")) 
                          (set! v2 (vertex-create "London")))
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜