请在 2024 年 Clojure 状况调查! 中分享您的想法。

欢迎!请查阅 关于 页面以获取更多有关此工作方式的信息。

0
错误

我在实现一个小的 Lisp 解释器,这使我发现了 case 实现中的这个错误。

(case "s"
  'quote "quote"
  "default")

;; Syntax error macroexpanding case at (org:localhost:56082(clj)*:131:16).
;; Duplicate case test constant: quote

我认为这可能是一个好的解决方案。

(case 'quote
  (symbol "quote") "quote"
  "default")
;; => "default"

这不工作,它返回 "default"。

奇怪的是,尽管 (symbol quote) 将是无效的,因为 quote 是未绑定的,但是这个快捷键 "work" 并返回 "quote"

(case 'quote
  (symbol quote) "quote"
  "default")
;; => "quote"

非常奇怪。看看这个。让我们尝试一个 'face 的例子。它会返回什么?

(case 'quote
  'face "face"
  "default")
;; => "face"

它会匹配 'quote

实际上,任何被引用的内容都会匹配。

(case 'quote
  (quote 123) "123"
  "default")
;; => "123"

希望这对于熟悉 case 宏展开的人来说,足以理解。

祝您一切顺利!

1 个答案

+1

已被选择
 
最佳答案

这是根据文档字符串的预期行为,不是错误。
'foo => (quote foo)
这发生在读取器中,根据 case 文档字符串,您可以有 (constant constant constant...),所以这是这对常量符号 quotefoo

这就是为什么你的代码中对表达式 'quote' 上的 case 操作与 'face' 匹配,因为它是由常量表达式 quoteface 组成的对。

类似地,(symbol quote) 是由常量表达式 symbolquote 组成的对(而且,再次强调,你的测试表达式匹配上了)。

根据文档说明:"测试常量不会被计算。它们必须是编译时字面量,并且不必加引号。"

如果刚才的说明还不够清楚,那么 'quote' 不合法的原因是因为读取器将其扩展为 (quote quote),现在你有了重复的常量表达式。

by
太棒了,感谢你的出色解释!
by
此内容并非原始问题的一部分,但重要的是要注意: ClojureScript会在 `case` 中计算常量符号(这一点在“与Clojure的差异”中有所暗示 https://script.clojure.org/about/differences)。
...