iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 22
0
Software Development

擁抱 Clojure系列 第 22

[第 22 天] 擁抱 Clojure:讀取器與詮釋資料(一)

讀取器與詮釋資料

你就要開始讀伊塔羅•卡爾維諾的新小說《如果在冬夜,一個旅人》。

— 卡爾維諾《如果在冬夜,一個旅人》

Clojure 程式開始於一串文字,經由讀取器 (Reader) 把程式轉化成資料結構;詮釋資料 (Metadata) 則是描述資料的資料,或者可以稱作元資料或中介資料。本篇文章將介紹讀取器以及詮釋資料的相關知識。

讀取器 (Reader)

形式 (Form)

Clojure 程式的生命由一串文字開始,讀取器 (Reader) 將文字解析之後,產生出編譯器 (Compiler) 可以認識的資料結構。

讀取器嘗試將文字解析成形式 (Form) 或稱作運算式 (Expression),而形式 (Form) 是指任何可以順利被求值 (Evaluation) 的合法程式單元。

任何可以順利被求值的程式單元,包括下列幾種:

符號 (Symbol)

任何以非數字開頭的文字皆是符號,符號名稱可以有四則運算字符以及問號,它的型態爲 clojure.lang.Symbol。

常值 (Literal)

常值 (Literal) 指的是程式中代表固定值的連續字符。Clojure 中的常值共有以下幾種:

  • 字串 (String)

    任何以雙引號 (") 包覆的字符會被看成字串,它的型態跟 Java 中的字串一樣,皆是 java.lang.String。

  • 數字 (Number)

    以數字字符開頭的連續字符,共有整數 (Integer)、浮點數 (Float) 以及有理數 (Ratio)。型態分別爲 java.lang.Long、clojure.lang.BigInt、java.lang.Double 以及 clojure.lang.Ratio。

  • 字符 (Character)

    字符以反斜線 (\) 開頭,與實際的字符相對應。型態爲 java.lang.Character。

  • nil

    代表虛無與不存在,與 Java 中的 null 相同意思。

  • 布林 (Boolean)

    truefalse 代表邏輯上的真與假。型態爲 java.lang.Boolean。

  • 關鍵字 (Keyword)

    由冒號 (:) 開頭的連續字符被當作關鍵字,與符號類似,大半用作索引值。型態爲 clojure.lang.Keyword。

列表 (List)

以左右小括號 (()) 圍起,內部可以是任何形式 (Form)。型態爲 clojure.lang.PersistentList。

向量 (Vector)

以左右中括號 ([]) 圍起,內部可以是任何的形式 (Form)。型態爲 clojure.lang.PersistentVector。

映射 (Map)

以左右大括號 ({}) 圍起,內部是索引與值的對應關係,稱爲向量。索引與值可以是任何的形式 (Form)。型態爲 clojure.lang.PersistentHashMap、clojure.lang.PersistentArrayMap 或 clojure.lang.PersistentTreeMap。

集合 (Set)

以大括弧 ({}) 圍起任何形式,並在前面加上井號 (#) 被當作集合。型態爲 clojure.lang.PersistentHashSet 或 clojure.lang.PersistentTreeSet。

讀取巨集 (Reader Macro)

有一些字符經由讀取器解析時,會執行特殊的行爲,這些字符被稱爲讀取巨集 (Reader macro)。在 LISP 程式語言中,除了內建的讀取巨集之外,使用者還可以自定讀取巨集,用以改變讀取器的行爲。而在 Clojure 中,讀取巨集則無法讓使用者自行訂製。

以下列出 Clojure 中會被視爲讀取巨集的各種字符:

單引號 (')

如果單引號 (') 放置在任何符號前面,將會抑制 Clojure 對符號求值,將該符號原封不動返回,這種行爲稱爲引用 (Quote)。 與使用 quote 函式功能一樣。

反斜線 (\)

而遇到反斜線 (\) 時,讀取器則會將它其後字符返回,成爲字符常值 (Character literal)。

分號 (;)

解析到分號 (;) 則會將其後的字符忽略不做解析,是爲註解 (Comment)。

小老鼠符號 (@)

小老鼠符號則是會呼叫 deref 函式,取出其後的參數所引導的值,稱爲標的 (De-reference)。用在取出參考類型所儲存的值,或是等待由 promisefuture 函式產生的延遲運算,計算完畢返回。

插入符號 (^)

插入符號 (^) 會伴隨着一個映射,其中是一些對於映射之後物件的描述資訊,這些資訊稱作詮釋資料 (Metadata)。與函式 with-meta 的功能一樣。

之後的小節將會有詮釋資料的詳細介紹。

井字符號 (#)

根據井字符號 (#) 之後的字符,讀取器會有不同的行爲,所以井字符號被稱作發派 (Dispatch) 巨集。以下是與井字符號搭配的各字符說明:

  • #{}

    集合。

  • #""

    正則表達式。

  • #'

    傳回之後符號所代表的 Var 物件,與 var 函式相同。

  • #()

    匿名函式。

  • #_

    之後的形式將會被讀取器忽略。

反引號 (`)

反引號 (`) (位置在鍵盤按鍵 1 左邊) 被稱爲語法引用 (Syntax quote),是 Clojure 巨集中使用的特殊符號之一,用來產生文字範本 (Template),範本中的形式將不會被求值。後續的章節將會有詳細的介紹。

波浪號 (~)

波浪號 (~) 被稱爲解引用 (Unquote),使用在反引號建立的文字範本內,讓波浪號後面跟隨的符號跳出範本而求值。

若波浪號 (~) 之後是小老鼠符號 (@),則被稱爲解引用拼接 (Unquote splice)。它的功用是將範本中的列表解消,替換成列表中的各個元素。

(未完待續)


上一篇
[第 21 天] 擁抱 Clojure:與 Java 共舞(三)
下一篇
[第 23 天] 擁抱 Clojure:讀取器與詮釋資料(二)
系列文
擁抱 Clojure30

尚未有邦友留言

立即登入留言