请分享您的想法,参加2024 年 Clojure 状态调查!

欢迎!请参阅关于页面了解更多关于如何使用此工具的信息。

+1
ClojureScript

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

我认为我可能发现了 ClojureScript 类型推断中的一个错误。我在这里创建了一个最小的复制品

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 推断的提示,因此不会影响此情况中的警告。它应该是没有 js 命名空间的^number

另外,请注意,ocall 是一个宏,因此它是否将您提供的元数据应用于源形式的输出形式由该宏决定。因此,它可能实际上没有到达需要的地方。

此外,考虑使用 (js/Math.random) 而不是 ocall。这像所有标准函数一样安全,同时也能正确地保留类型提示。

谢谢Thomas,非常感谢。

为了完整性,这个被剪裁的代码实际上调用了Vega JavaScript库中的函数:为了举例中的方便,我切换到`js.Math.random`,以避免需要导入Vega(过度简化的风险!)。

关于这一点有好的文档吗?我尝试过`^number`,得到了同样的警告,我也不知道有什么区别,或者 type hints 对宏无效这个事实?

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

在我看来,最好完全避开`ocall`这样的工具。
谢谢Thomas。

如果我想要彻底了解这个(例如,了解`^js/number`和`^number`之间的区别),我应该到哪里寻找可以帮助我理解的文档?
我对这方面的文档并不了解。但我相信确实有一些文档。

简单地说,编译器只识别少数几种类型提示。有“number”和“boolean”正是这样。然后是“js”和“js/*”,用于 externs 推理,基本上是告诉编译器收集 externs 以防止在`:advanced compilation`中进行重命名。

真正不同的是,它必须是 exact match,而“number”不等于“js/number”。
太好了。非常感谢你的帮助。
...