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

欢迎!想了解更多关于这个功能的信息,请查看关于页面。

+1
 tweak_image 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
 tweak_image
已选中
 
最佳答案

^js/number不是有效的数字提示。以js/开头的一切都被视为externs推断的提示,因此不会影响此处的警告。它应该是没有js命名空间的^number

此外,请注意,ocall是一个宏,是否将其元数据应用到源形式到输出形式取决于该宏。因此,它可能实际上不会到达需要的地方的编译器。

还可以考虑仅使用(js/Math.random)而不是ocall。这样就像所有标准函数一样,可以安全地从重命名环境中分离出来。这也会正确地保存类型提示。

by
感谢Thomas,非常感激。

为了完整性,我实际上是从Vega JavaScript库中调用的函数中裁剪出来的代码:为了避免需要导入Vega,我已经切换到`js.Math.random`(过度简化的风险!)。

关于这个有好的文档吗?我曾尝试过`^number`并得到相同的警告,并且我并不了解差异以及对宏类型提示无效的事实?

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

在我看来,为了避免完全使用ocall等,最好是避免。
by
感谢Thomas。

如果我想真正理解这个(比如,了解^js/number和^number之间的区别),我应该在哪里寻找帮助我理解的文档?
by
我不了解有关于此的文档。我相信一定有的。

简单来说,编译器只识别几种类型提示。分别是“number”和“boolean”,正好对应这两种类型。对于externs推断,基本上就是“js”和“js/*”,告诉编译器收集externs以防止在:advanced编译时的重命名。

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