为什么(零)的评价不同于((println"foo"))

Mar*_*tus 2 clojure

为什么下面最后两行的差异?评估异常从REPL粘贴.我正在使用Clojure 1.4

(println "foo") ;; evals to nil

(nil)  ;; CompilerException java.lang.IllegalArgumentException: Can't call nil
((println "foo")) ;; NullPointerException
Run Code Online (Sandbox Code Playgroud)

A. *_*ebb 8

一个是编译时异常; 另一个是运行时异常.

(nil)编译器看到您正在尝试调用函数nil并给出编译错误的情况下.

((println "foo"))编译器的情况下,不会尝试推断内部表单(println "foo")将返回什么.总而言之,它知道它可以返回一个函数,因此在编译时不会进行检查.在确实println返回a nil并且您尝试调用它时,在运行时发生异常.

作为动态语言意味着您通常不会尝试在编译时检测变量的类型错误.

注意:

(.setDynamic #'println)

(binding [println 
           (fn [x] 
             (when (pos? (rand-int 2)) 
               (fn [] (print "bar\n"))))] 
  ((println "foo")))
Run Code Online (Sandbox Code Playgroud)

它将随机打印"bar"并返回nil,没有运行时异常或者不打印任何内容并抛出运行时NullPointerException.这里显然这个设计println没有静态返回类型供编译器检测.

但编译器仍然可以检测仅涉及值的类型错误.