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

欢迎!请参阅关于页面以了解更多有关此操作的信息。

+1
ClojureScript

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

请注意,ocall 是一个宏,因此是否将您提供的元数据应用于源形式以生成输出形式取决于该宏。因此,它可能根本不会到达编译器需要它的地方。

另外,考虑只使用 (js/Math.random) 而不是 ocall。这是安全的,就像所有标准函数一样避免重命名。这还将正确地保留类型提示。

感谢Tom,非常感激。

为了完整性,实际上从中截取的代码确实调用了Vega JavaScript库中的函数:为了示例的简洁性,我改用`js.Math.random`以避免导入Vega(过度简化的风险!)。

有关于此的好文档吗?我曾尝试过`^number`并收到相同的警告,而我并不了解这之间的区别,或者类型注解对宏不适用的事实?

再次感谢!
类型注解对宏同样适用,但请记住,宏是接受一个形式并返回另一个形式的函数。如果宏没有明确地将从输入接收到的元数据“传递”到输出,它将丢失。我猜`ocall`没有这样做,但我不确定。

在我看来,最好完全避免ocall这类操作进行互操作。
感谢Tom。

如果我想要彻底了解这一点(例如,了解^js/number和^number之间的区别),我应该在哪里寻找帮助我理解的文档?
我不了解这方面有任何文档。但肯定有。

简而言之,只存在几种编译器可识别的类型注解。有“number”和“boolean”,正好对应这个。然后是“js”和“js/*”,用于基本的externs推断,告诉编译器收集externs以保护在:advanced编译中的重命名。

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