我在學習 clojure 的時候,有一個思考一陣子的問題:「程式語言之間的溝通傳輸的格式,要選用 JSON 還是 EDN 。如果使用 EDN 的話,會有什麼明確的好處嗎?」
考慮如下的例子:
要傳遞的資料,有「時間」的資料型態。而中間的傳輸格式,需要使用 rfc 3339
在 EDN 裡,時間可以直接儲存成 rfc 3339 的格式
#inst "1985-04-12T23:20:50.52Z"
由於 EDN 已經有數種語言的實作可以用,下方是 python3 的範例。
如果傳送的資料格式是用 json 。而且傳遞的資料型態,恰好有一個是 rfc 3339 。 python 的 application logic 就會包含 (1) json.loads() 和 (2) 一個特定的用來處理 rfc 3339 的邏輯。
與之相對的是,直接用 EDN format ,則是使用 edn_format.loads() 就可以搞定。
相差不多,只差一點點。後者可以讓 application logic 乾淨一點。因為減少了 context dependency 。所謂的 context dependency 就是指為了某些「json 沒有的 data type 」而花力氣去寫的 marshal/unmarshal logic 。
=================================================================
最後,那 EDN 到底跟 clojure 有什麼關系呢? EDN 的延伸資料型態 (extension elements),可以使用標記元素 (tagged element) 去表現。 比方說,rfc3339 就是一種內建的延伸資料型態。 uuid 則是另一種內建資料型態,長成這樣子:
#uuid "f81d4fae-7dec-11d0-a765-00a0c91e6bf6"
使用者自訂的延伸資料型態,則是長成這個樣子:
#myapp/Person {:first "Fred" :last "Mertz"}
也因為格式的定義如此,每次要對 EDN 增加一種延伸的資料型態時,就是對 EDN 的 parser (每一種語言會有各自的實作) 寫出該種延伸資料型態的 parser plugin ,在 Clojure 的世界也可以稱之為 read macro ,再將這個 parser plugin 註冊到該種資料型態使用的標記元素之後, 這個 EDN parser 就可以無縫地運作。 marshal/unmarshal logic 也就可以完美地放進 parser 裡,不會混淆在 application logic 裡了。
Showing posts with label edn. Show all posts
Showing posts with label edn. Show all posts
Wednesday, September 6, 2017
What made lisp different?
Paul Graham 的文章 Waht made lisp different 真的好難懂。不過,我最近也寫過了 Clojure 的 macro ,疑似有理解一些了。
The whole language always available. There is no real distinction between read-time, compile-time, and runtime. You can compile or run code while reading, read or run code while compiling, and read or compile code at runtime.
這一段舉了四個例子來說明:
1. Running code at read-time lets user reprogram Lisp's syntax.
這是在講 Read macro 。
Common Lisp 的 read macro 是 reader 的 plugin ,可以註冊在 reader 裡。 而 Clojure 的話,內建了許多 read macro,但是不開放『自訂 read macro 』的功能。
2. Running code at compile-time is the basis of macros.
macro 可以視為是 compiler 的 plugin 。 在 Clojure 的例子是用 defmacro 。
3. Compiling at runtime is the basis of Lisp's use as an extension language in program like Emacs.
在 Clojure 的例子,使用 clojure.core/load , clojure.core/require 可以在執行期間啟動 compiler 。在 Riemann monitoring system 裡,就是利用 clojure.core/load 來讓 clojure 作為 Riemann 本身的 extension language 。而類似的 monitoring system 比方說像 Kapacitor 的話,則是還要特別定義一個專用的 extension language 。
4. Reading at runtime enables programs to communicate using s-expressions, an idea recently reinvented as XML.
在 Clojure 的例子,最接近的函數應該是 clojure.edn/read ,因為可以用於 untrusted source 。在 javascript 則是 JSON.parse() 。現代 web application 的前後端溝通所使用的 json 格式,也可以視為是一種 reading at runtime 特性的應用。
The whole language always available. There is no real distinction between read-time, compile-time, and runtime. You can compile or run code while reading, read or run code while compiling, and read or compile code at runtime.
這一段舉了四個例子來說明:
1. Running code at read-time lets user reprogram Lisp's syntax.
這是在講 Read macro 。
Common Lisp 的 read macro 是 reader 的 plugin ,可以註冊在 reader 裡。 而 Clojure 的話,內建了許多 read macro,但是不開放『自訂 read macro 』的功能。
2. Running code at compile-time is the basis of macros.
macro 可以視為是 compiler 的 plugin 。 在 Clojure 的例子是用 defmacro 。
3. Compiling at runtime is the basis of Lisp's use as an extension language in program like Emacs.
在 Clojure 的例子,使用 clojure.core/load , clojure.core/require 可以在執行期間啟動 compiler 。在 Riemann monitoring system 裡,就是利用 clojure.core/load 來讓 clojure 作為 Riemann 本身的 extension language 。而類似的 monitoring system 比方說像 Kapacitor 的話,則是還要特別定義一個專用的 extension language 。
4. Reading at runtime enables programs to communicate using s-expressions, an idea recently reinvented as XML.
在 Clojure 的例子,最接近的函數應該是 clojure.edn/read ,因為可以用於 untrusted source 。在 javascript 則是 JSON.parse() 。現代 web application 的前後端溝通所使用的 json 格式,也可以視為是一種 reading at runtime 特性的應用。
Subscribe to:
Posts (Atom)