iT邦幫忙

2017 iT 邦幫忙鐵人賽
DAY 3
0
Big Data

資料科學:使用 Clojure系列 第 3

Day 03 - Clojure 基礎知識(三)

Macro

Macro(宏、巨集)在程式語言中是一個使用者自訂的程式語言擴展。在 Lisp 系語言中,macro 的威力相當強大,主要是來自於 Lisp 系語言的「程式碼 - 資料結構同像性」(homoiconic)。這裡簡單紀錄 Clojure 的求值模型。

(defmacro backwards
  [form]
  (reverse form))

(backwards (" backwards" " am" "I" str))
; => "I am backwards"

在 Lisp 系語言中,list 的第一個字必須處理下面的東西,然而,通過 macro,使得特殊形式的語法可以被接受。

Clojure 的求值步驟由兩部組成:

  1. 讀入程式碼,產生 Clojure 數據結構
  2. 求值數據結構,並在讀取過程中針對不同了類型進行相應的變數查找、函數呼叫等。

在多數語言中,程式碼首先被轉換成 AST(抽象語法樹)結構。在 Clojure 中,S-expression 本身就是與 AST 等價的結構了。原文提到了篇不錯的文章〈Syntax and Semetics〉

Reader

在 Clojure 中,使用 read-string 讀入程式碼。這個函數接受一個字串參數,然後返回處理後的數據結構。接著可以把數據結構傳給其他函數,也可以用 eval 求取結果。在 Clojure 資料結構中,主要有下列四種形式。

  • (a b c) 是一個 list 結構
  • str 符號(symbol)結構
  • [1 2] 是一個 vector 結構
  • {:a "b"} 是一個 map 結構

這些可以原生轉換。不過,對於 lambda(匿名函數),例如 #(+ 1 %) 這類的,將被 reader macros 轉換為以 Clojure 關鍵字表達的形式。'#@ 都是 macro 標誌。

  • ' 會用 quote 展開
  • # 會用 fn 展開
  • @ 會用 deref 展開

註解則不展開。

Evaluator

List 的第一個元素會被程序搜尋對應的函數。而不是第一個元素且也不是 list 的其餘元素求值為自身,包括 truefalse{}:keyword

接著會查找由 def 根據地一個元素是否有前綴(prefix)在對應的命名空間建立的「符號-值」表查找對應的值(可能是個函數,或者是其他 macro)。順序如下:

  1. 是否為特殊形式?(保留字,如 fnif
  2. 是否為當前表達式特殊綁定?(例如在 let 下),越內部的解析優先權越高。
  3. 是否在某個命名空間中存有綁定?
  4. 報錯

另外就是函數調用時,會先對每個元素都完全求值,才做為參數傳遞


上一篇
Day 02 - Clojure 基礎知識(二)
下一篇
Day 04 - Clojure 基礎知識(四)
系列文
資料科學:使用 Clojure30

尚未有邦友留言

立即登入留言