Macros 以编程方式填写letrec in方案。宏还是评估?

Macros 以编程方式填写letrec in方案。宏还是评估?,macros,scheme,Macros,Scheme,我只是在玩NFA来识别字符串。我有一个宏,它创建一个函数,该函数使用输入并将其余的传递给其他函数。因为我的NFA图中可能有循环,所以我使用letrec将整个过程放在一起。以下是一些代码(已在PLT方案中测试): 现在,如果我有一个简单的数据结构来表示我的NFA,比如列表列表。e、 g '((s4 () () #t) (s3 (c) (s4) #f) ...) 我的问题是:我如何将该列表转化为前letrec声明?我不太擅长宏,我的理解是我可能不应该使用eval 如果列表在编译时已知(我

我只是在玩NFA来识别字符串。我有一个宏,它创建一个函数,该函数使用输入并将其余的传递给其他函数。因为我的NFA图中可能有循环,所以我使用letrec将整个过程放在一起。以下是一些代码(已在PLT方案中测试):

现在,如果我有一个简单的数据结构来表示我的NFA,比如列表列表。e、 g

'((s4 () () #t)
  (s3 (c) (s4) #f) 
  ...)

我的问题是:我如何将该列表转化为前letrec声明?我不太擅长宏,我的理解是我可能不应该使用eval

如果列表在编译时已知(我的意思是,在程序开始运行之前),则可以使用宏。否则必须使用
eval


没关系。这是评估的良好用途之一。:)

我想出了这个宏,它似乎可以完成这项工作 (我也不是专家):

诀窍是使用中间形式创建“子替换循环”, 和保留标识符(参见
let bindings
)来区分这些中间形式
直接使用宏。

我认为您的问题可以分为两个子问题:

  • 编写一个使用NFA描述并自动生成NFA的宏,我称此宏为生成NFA
  • 将make NFA应用于通过编程生成的列表,我将此宏称为应用宏
  • 第二个子问题很简单:

    (define-syntax apply-macro
      (syntax-rules ()
        ((_ macro ls)
         (eval 
          `(macro ,@ls)
          (interaction-environment)))))
    ;(define ls '(1 2 3))
    ;(apply-macro if ls)=>2
    
    第一个问题,我有一个DFA样本,你可以自己写一个NFA:

    (define-syntax make-DFA
      (syntax-rules (: ->)
        ((_ init-state (state : result (symbol -> next) ...) ...)
         (letrec 
             ((state 
               (lambda(sigma)
                 (cond
                   ((null? sigma) result)
                   (else
                    (case (car sigma)
                      ((symbol) 
                       (next (cdr sigma)))...
                      (else false))))))... )
           init-state)))) 
    
    (define DFA1
      (make-DFA q1
                 (q1 : true (#\a -> q2)
                     (#\b -> q3))
                 (q2 : false (#\a -> q1)
                     (#\b -> q4))
                 (q3 : false (#\a -> q4)
                     (#\b -> q1))
                 (q4 : true (#\a -> q3)
                     (#\b -> q2))))
    (DFA1 (string->list "ababa"));=>#f
    

    嗯,也许define macro是实现apply macro的更好方法。

    出于好奇,有没有理由将
    match
    作为一个宏而不是一个常规函数?调用函数会导致对参数进行求值,这需要避免让letrec工作。+1。我感谢你的辛勤工作和榜样,但我的问题是我的列表是按程序生成的。比如说,为了便于示例,它存储为
    nfa规则
    ,开始是
    s1
    。然后我希望能够执行
    (nfa s1 nfa规则)
    。让宏“窥视”nfa规则并迭代内容是我遇到的问题。我认为Jason所说的可能是正确的。如果我在编译时知道这个列表,我可以使用你的宏来简化编码。但是,如果列表是以编程方式生成的,我可能必须在运行时使用
    eval
    将其转换为适当的代码。如果您要将NFA作为数据进行操作,那么将其作为数据来实现可能会更简单,并且当您必须在代码中硬编码某些NFA时,使用宏只是为了便于输入。你的letrec/macro技巧很巧妙,但是:-)而且,没有一个宏会“窥探”任何变量:在进行任何计算之前,它们会操作代码,所以就它们而言,
    nfa规则
    只是一个词。听你这么说重申了我认为是正确的。除非有人证明不是这样,否则你会被选中。
    (define-syntax apply-macro
      (syntax-rules ()
        ((_ macro ls)
         (eval 
          `(macro ,@ls)
          (interaction-environment)))))
    ;(define ls '(1 2 3))
    ;(apply-macro if ls)=>2
    
    (define-syntax make-DFA
      (syntax-rules (: ->)
        ((_ init-state (state : result (symbol -> next) ...) ...)
         (letrec 
             ((state 
               (lambda(sigma)
                 (cond
                   ((null? sigma) result)
                   (else
                    (case (car sigma)
                      ((symbol) 
                       (next (cdr sigma)))...
                      (else false))))))... )
           init-state)))) 
    
    (define DFA1
      (make-DFA q1
                 (q1 : true (#\a -> q2)
                     (#\b -> q3))
                 (q2 : false (#\a -> q1)
                     (#\b -> q4))
                 (q3 : false (#\a -> q4)
                     (#\b -> q1))
                 (q4 : true (#\a -> q3)
                     (#\b -> q2))))
    (DFA1 (string->list "ababa"));=>#f