【问题标题】:how to understand this problem in cs61a about scheme macro?如何理解cs61a中关于方案宏的这个问题?
【发布时间】:2021-08-10 03:04:52
【问题描述】:

我看不懂cs61A中的宏例子,谁能告诉我什么时候操作evals?

scm> (define (twice f) (begin f f))
twice
scm> (twice (print 'woof))
woof

我知道 (print 'woof) 第一个 eval 为 None 并绑定到 f,然后 return (begin None None) 为 None

但是

scm> (define (twice f) (begin f f))
twice
scm> (twice '(print 'woof))
(print (quote woof))

这让我很困惑......

'(print 'woof) 第一个 eval 为 (print 'woof) 并绑定到 f,然后 在两次函数中应该返回 (begin (print 'woof)(print 'woof)) 那么为什么不打印两次 woof 呢?

【问题讨论】:

    标签: macros scheme


    【解决方案1】:

    我希望您使用 Racket。所以,begin 的文档说:

    (开始形式...)

    (开始表达式 ...+)

    第二种形式适用于在表达式位置开始。在这种情况下,将按顺序计算 expr,并且除了最后一个 expr 之外的所有结果都将被忽略。

    在您的示例中,'(print 'woof) 的计算结果为 (print 'woof),这是正确的。但是,(begin f f) 会根据上述规则进行评估。 f 在这里是expr,所以f 被评估,结果是(print 'woof),第二个f 被评估,结果是(print 'woof),最后,只返回最后一个结果,那就是(print 'woof)

    换句话说,您的函数返回的不是(begin (print 'woof) (print 'woof)),而是(begin f f)

    要得到你想要的结果,twice 必须是宏。

    (define-syntax twice
      (syntax-rules ()
        ((_ expr) (begin expr expr))))
    

    你可以这样检查扩展:

    > (syntax->datum
         (expand-to-top-form
          '(twice (print 'woof))))
    '(begin (print 'woof) (print 'woof))
    

    你这样称呼它:

    > (twice (print 'woof))
    'woof'woof
    

    【讨论】:

    • 结果肯定是woofwoof,而不是'woof'woof?我看不出报价最终会如何出现在输出中。 (好的,经过一些测试,我发现这取决于您使用的方案。在 Racket 中,确实可以得到引号,但我们可以看到问题使用了另一种方言,其中 print 不引用符号,基于最后一个 sn -p. 在该方言中,引号将为零。
    • 在语言设置中,选择语言,显示详细信息,我将输出样式设置为打印。如果我把它改成写,结果将是woofwoof
    猜你喜欢
    • 2019-11-10
    • 1970-01-01
    • 2014-12-14
    • 2011-08-30
    • 2020-12-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-17
    相关资源
    最近更新 更多