Clojure关于类型推断的不足

Clojure关于类型推断的不足,clojure,type-inference,Clojure,Type Inference,这段代码不是我的“真实”代码,而是一个更大算法的示例。我花了一段时间才发现(使用(set!*反射时发出警告*true))反射是问题所在 随着类型暗示出现在动态语言(例如python和clojure)中,而攻击性类型推断出现在其他语言(例如Scala)中,我不得不使用(int…)进行显式转换似乎有些奇怪 为什么clojure不知道(aget int array int)返回一个int 我可以自己注释if语句,说它返回int吗 如果没有,我可以使用内联函数来避免重新感染 (let [a (int-a

这段代码不是我的“真实”代码,而是一个更大算法的示例。我花了一段时间才发现(使用
(set!*反射时发出警告*true)
)反射是问题所在

随着类型暗示出现在动态语言(例如python和clojure)中,而攻击性类型推断出现在其他语言(例如Scala)中,我不得不使用
(int…
)进行显式转换似乎有些奇怪

为什么clojure不知道
(aget int array int)
返回一个int

我可以自己注释if语句,说它返回int吗

如果没有,我可以使用内联函数来避免重新感染

(let [a (int-array [4 5 6 7])]
   ;(aset a 1 (int (if (seq a) 40 (aget a 0))))) ;; fast
    (aset a 1      (if (seq a) 40 (aget a 0))))  ;; slow

我知道类型暗示的类型不亚于此
int
调用,但在更复杂的代码中可能不是这种情况。

注意:从Clojure 1.8.0开始手动测试

为什么clojure不知道(aget int array int)返回一个int

是的。它似乎不知道的是
(如果长int)
返回一个可能被强制为原始int的结果。请注意,如果改为编写
(int 40)
,反射警告将消失

我可以自己注释if语句,说它返回int吗

使用
(int…
确实是一种方法。在这种情况下,int类型的提示是不正确的,因为正如我们所看到的,这个表达式可能返回一个long

随着类型暗示出现在动态语言中(例如python和clojure),而攻击性类型推断出现在其他语言中(例如Scala),我不得不使用(int…)进行显式转换似乎有些奇怪


Clojure本质上是一种动态类型语言。Clojure编译器已经进行了相当多的类型推断——特别是在本地进行的——但这仍然是在尽最大努力的基础上进行的,我认为不应该期望其他任何事情(请记住,不知道程序中流动的值的类型是动态类型的一个特性)。诚然,您粘贴的特定代码片段可以接受相当多的静态分析,但在一个典型的真实世界程序中,值通过许多中介,这样广泛的分析甚至不可行-因此,编译器为什么要不遗余力地支持它?

Clojure是java长对象。这就是为什么如果要避免反射调用,必须在代码中将其显式强制为int本机jvm值的原因。@kawas44感谢您在接受的答案的第一部分添加了透视图。首先,看一看aset int,它似乎就是您想要的。可能不相关,但我看到其他人在这个问题上绊倒了,我想我应该提一下。在clojure中,只有在需要传递/接收java数组的java互操作时,才倾向于使用int-array、aget、aset等。如果您只是在clojure级别工作,那么您只需要使用clojure向量。提到它是因为我见过来自其他语言的人,特别是java,他们认为他们需要使用aget/aset来完成使用数组的算法。clojure向量是一个数组。@TimX Great point
aset int
解决了反射问题,无需额外调用
(int…
(int 40)
也能正常工作。我怎么也猜不到!谢谢你解释原因。