2024 Clojure状态调查!中分享您的想法。

欢迎!请参阅关于页面了解此工作原理的相关信息。

+1 投票
ClojureScript

关于 Slack 中 ClojureScript 主题的最近一次对话,Dan Sutton 建议我在这里创建一个问题。

我认为我可能在 ClojureScript 的类型推断中找到了一个 bug。我在这里创建了一个最小化的复现

https://github.com/paulbutcher/clojurescript-type-inference-bug

以下代码生成了一个警告

  cljs.core/-, all arguments must be numbers, got [#{js/clj-nil clj-nil} #{js/clj-nil clj-nil}] instead
  (- (ocall js/Math :random) (ocall js/Math :random))
  ^---

我预计可以这样修复它

(- ^js/number (ocall js/Math :random) ^js/number (ocall js/Math :random))

但它给了我完全相同的错误。

1 个答案

0 投票

已选择
 
最佳答案

^js/number 不是一个有效的数字提示。任何以 js/ 开头的或都被视为 externs 推断的提示,因此它不会影响此情况下的警告。应该只使用 ^number 而不包含 js ns。

此外,请注意 ocall 是一个宏,是否将您提供的元数据应用到源形式并传递到输出形式取决于该宏。因此,它可能实际上并没有到达编译器需要的位置。

还可以考虑仅使用 (js/Math.random) 而不是 ocall。这与所有标准函数一样,免于重命名。这将正确保留类型提示。

谢谢托马斯,非常感谢。

仅仅为了完整性,这段代码实际上调用了Vega JavaScript库中的函数:我切换到`js.Math.random`是为了避免需要导入Vega(过度简化的危险!)。

是否有关于这方面的良好文档?我尝试过`^number`,但得到相同的警告,而且我并不知道它们之间的区别,或者类型提示对于宏不起作用的事实?

再次感谢!
类型提示对于宏也可以正常工作,但请记住,宏是接收一种形式并返回另一种形式的函数。如果宏没有明确地将从输入接收到的元数据“传递”到输出,它将会丢失。我猜`ocall`不会这样做,但我不确定。

在我看来,最好完全避免`ocall`这样的函数进行交互。
谢谢托马斯。

如果我想要真正弄清楚这一点(例如,了解`^js/number`和`^number`之间的区别),我应该去哪里寻找能够帮助我理解的文档?
我不知道有关这方面的文档。但肯定有的。

简单来说,编译器只识别少数几种类型提示。确切地说,有“数字”和“布尔”类型。然后就是“js”和“js/*”,主要用于外部推断,告诉编译器收集外部符号以保护在:高级编译中的重命名。

实际的区别在于,它需要完全匹配,“数字”不等于“js/number”。
by
太好了。感谢您的帮助——非常感激。
...