ClojureScript

1.10.516 版本發佈

2019 年 1 月 31 日
ClojureScript 團隊

值得注意的變更

Spec instrumentation (cljs.spec.test.alpha/instrument 和相關功能) 不再需要 test.check。如果您使用 cljs.spec.test.alpha/check,則需要 test.check 的資料產生功能;在這種情況下,您需要引入 clojure.test.checkclojure.test.check.properties 命名空間。

cljs.spec.test.alpha/check API 中與 Spec 使用 test.check 相關的關鍵字現在以 clojure.spec.test.check 限定,從而與 Clojure 對齊。仍然支援先前使用 clojure.test.check 限定的方式。

Clojure 1.10 功能

改進的例外訊息和列印

Clojure 1.10 中新增的改進的例外基礎架構已在此版本中移植到 ClojureScript。

透過 Metadata 的協定

透過 Metadata 新增協定 (對於使用 :extend-via-metadata true 指令定義的協定) 的功能已在此版本中移植到 ClojureScript。

Datafy 和 Nav

clojure.datafy 命名空間已移植到 ClojureScript,以及 clojure.core.protocols 命名空間中的相關協定。

clojure.edn 命名空間

此版本新增了一個新的 clojure.edn 命名空間,它將功能委派給 cljs.reader。這有助於編寫可移植的 Clojure / ClojureScript 原始碼,並利用 clojure.edn/readclojure.edn/read-string

型別推斷改進

謂詞誘導的型別推斷

現在,型別推斷演算法會在推斷條件運算式中使用的區域變數的型別時考慮核心謂詞。

例如,在

(if (string? x)
  (inc x)
  10)

因為 x 滿足 string?,所以會在 then 分支中推斷為字串型別 (因此會發出警告,因為 inc 被應用於它)。

因為 condwhen 是基於 if 建構的巨集,所以謂詞誘導的推斷也適用於涉及 condwhen 的運算式。

除了核心謂詞外,謂詞誘導的型別推斷也適用於 instance? 檢查。因此,例如測試 (instance? Atom x) 將導致 x 被推斷為 cljs.core/Atom 型別。

真值誘導的推斷

在值可能為 nil (在型別標籤中以符號 clj-nil 表示) 的情況下,如果將引用此值的簡單符號用作條件中的測試,則型別推斷演算法會推斷該值在 then 分支中不能為 nil

這或許最好用範例來說明。假設您有以下函式

(defn f [x]
  (when (even? x)
    (inc x)))

此函式的回傳型別為 #{number clj-nil},表示可以回傳數字或 nil

以下函式使用 f,先前會被推斷為回傳 #{number clj-nil},現在則被推斷為回傳 number

(defn g [y]
  (let [z (f y)]
    (if z
      z
      17)))

事實上,由於 or 巨集的展開方式,現在運算式 (or (f 1) 17) 會被推斷為簡單的 number

改進的 loop / recur 推斷

現在,型別推斷演算法會在推斷 loop 區域型別時考慮 recur 參數型別。

例如,在

(loop [x "a"]
  (if (= "a" x)
   (recur 1)
   (+ 3 x)))

先前會將區域變數 x 推斷為字串型別 (這會導致發出將其加到 3 的運算式的警告)。現在,編譯器會將 x 推斷為字串或數字型別 (因此警告將不再出現)。

多重參數和可變參數函式回傳型別推斷

ClojureScript 1.10.439 新增了函式回傳型別推斷,但此功能僅適用於單參數函式。此版本將此功能擴展到多參數和可變參數函式。

此外,如果不同的參數回傳不同的型別,則推斷的回傳型別會正確變化。例如,

(defn foo
  ([x] 1)
  ([x y] "a"))

那麼運算式 (foo true) 會被推斷為數字型別,而 (foo :a :b) 會被推斷為字串型別。

Spec 改進

此版本中對 Spec 實作進行了多項改進,使得在標準核心函式庫中更容易指定函式,並在程式碼庫中有大量函式具有 Spec 時提高 instrumentation 效能。

效能改進

Ranges 的 Chunked-Seq 支援

ClojureScript 現在支援 Ranges 的 chunked-seqs。此功能可提高效能的範例是

(reduce + (map inc (map inc (range (* 1024 1024)))))

在 V8 中評估速度快 5 倍,在 SpiderMonkey 中快 7 倍,在 JavaScriptCore 中快 2 倍。

改進的 re-seq 效能

re-seq 的效能已得到改進,在主要的 JavaScript 引擎下速度提高了 1.5 倍或更多。

最佳化的字串運算式串連

一般而言,提供給 str 函式的引數會先被強制轉換為字串,然後再串連。在此版本中,對於推斷為字串型別的引數,會消除不必要的強制轉換,從而產生更精簡的程式碼產生,並提高速度。

例如,在

(defn foo [x y]
  (str (+ x y)))

(str (name :foo/bar) "-" (foo 3 2))

由於改進的程式碼產生,最後一個 str 運算式在 V8 中的評估速度快 3 倍,在 JavaSriptCore 中快 4 倍。

變更清單

如需 ClojureScript 1.10.516 中更新的完整清單,請參閱 變更

貢獻者

感謝所有為 ClojureScript 1.10.516 做出貢獻的社群成員

  • Anton Fonarev

  • Enzzo Cavallo

  • Erik Assum

  • Eugene Kostenko

  • Martin Kučera

  • Michiel Borkent

  • Oliver Caldwell

  • Sahil Kang

  • Thomas Heller

  • Thomas Mulvaney

  • Timothy Pratley

  • Will Acton