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`,也得到了相同的警告,并且我不知道两者之间的区别,或者不知道类型提示对于宏是不起作用的?

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

在我看来,最好根本避免使用ocall这样的东西进行互操作性。
感谢Thomas。

如果我想彻底了解这一点(例如,了解^js/number和^number之间的区别),我应该去哪里寻找有助于我理解的文档?
我并不知道有关这一点的任何文档。但我确信这样的文档是存在的。

简单来说,编译器只能识别几种类型提示。有用于数值的“number”和用于布尔值的“boolean”。还有“js”和“js/*”用于externs 推理,基本相当于通知编译器收集externs 以保护在:advanced 编译中的重命名。

其实区别就在于它需要一个确切的匹配,“number”并不等同于“js/number”。
by
太好了。感谢您的帮助——非常感激。
...