這是介紹Clojure - data structure的collection系列四篇中的第一篇~
(編按:今天一早就去爬山走了17km⛰️ 所以比較晚發文 ^^")
話說在Day2踏 上Clojure / Clojurescript的旅程 - 學習Clojure語法的勇敢與真實文章裡面,曾經有個簡單的舉例
(def harry-potter-series
["the Philosopher's Stone" "the Chamber of Secrets" "the Prisoner of Azkaban"])
其中
["the Philosopher's Stone" "the Chamber of Secrets" "the Prisoner of Azkaban"])
但是在clojure []
就是代表Vector
啦!
在vector拿出index為2的element:
tutorial.core=> (get ["the Philosopher's Stone" "the Chamber of Secrets" "the Prisoner of Azkaban"] 2)
"the Prisoner of Azkaban"
這個[]
的結構在其他的程式語言通常叫做Array
;
我想取名做Vector
的原因可能是因為clojure是從LISP(created by John McCarthy in 1958)被啟發的,LISP這種語言本質上不是一種技術,而是數學。而Vector也是數學的[]
英文名字,代表向量符號。(不負責任亂猜?)
題外話,如果想對於LISP有更深入的了解,可以看(Structure and Interpretation of Computer Programs, SICP)關於計算機程式設計的基礎教程影片。作者是麻省理工學院的教授Harold Abelson 、Gerald Jay Sussman。敝公司的前輩大大們強力推薦
效法Day03 比較Javascript vs Clojurescript的文章來比較一下js & cljs,
Javascript | Clojurescript |
---|---|
Array | Vector |
['T', 'I', 'N', 'G'] | ["T" "I" "N" "G"] (不可使用單引號包住string) |
在其他語言像是Javascript、Ruby等,Array裡的element,其值是可以被覆寫的
my_book_names = [
"the Philosopher's Stone",
"the Chamber of Secrets",
"the Prisoner of Azkaban"
]
my_book_names[0] = "the Rolling Stone"
my_book_names
# => [
"the Rolling Stone",
"the Chamber of Secrets",
"the Prisoner of Azkaban"
# ]
以ruby為例
以javascript為例
但在Clojure,當你增加element到Vector裡,你會得到一個新的Vector,而且原本的Vector資料是永遠不變的immutable
。
我找了2021年關於immutable的討論串以下是關於設計成immuatable的好處:
In clojure, as in other functional programming environments, a vector is also a stateless, immutable, mathematical entity. Which is nice because nobody can change its state out from under you and that makes programs easier to reason about.
There are also specific use cases where this feature may shine in a specific way, for example making it easy to maintain an "undo history" when implementing a text editor.
說到implementing a text editor,大型的社群網站Facebook,塗鴉牆的每篇文章就像是一個個text editor,不是嗎?:)
因此在這篇stackoverflow文章 - Why is immutability so important (or needed) in JavaScript?就有提到,
由facebook opensource的專案Immutable-JS library、
React JS
和React Native,
都實作了這種immutability(不可變性),
替資料增加了可預測性(predictability),可追蹤性(allows for mutation tracking)及增進效能(performance) 。真是好處多多呢!
鐵人賽之後預計會討論到的Reagent套件,也就是個可幫助我們有效率地寫React components的ClojureScript interface。
除了本文第一段提到的get
用法,另外還想簡單介紹極為常用的conj
及assoc
把element塞到一個Vector裡:
"the Philosopher's Stone",
"the Chamber of Secrets",
"the Prisoner of Azkaban"
(conj ["the Philosopher's Stone"] "the Chamber of Secrets", "the Prisoner of Azkaban")
=>
["the Philosopher's Stone" "the Chamber of Secrets" "the Prisoner of Azkaban"]
把Vector塞到另一個Vector裡:
(conj ["Harry Potter"] ["the Philosopher's Stone"] ["the Chamber of Secrets"] ["the Prisoner of Azkaban"])
=>["Harry Potter" ["the Philosopher's Stone"] ["the Chamber of Secrets"] ["the Prisoner of Azkaban"]]
跟上面提到的immutable概念很有關係,官方文件說到assoc會回傳一個新的vector,並且把指定的index的值取代掉
When assoc applied to a vector, returns a new vector that contains val at index.
Note - index must be <= (count vector)
舉一個讓大家好記的例子做收尾~
(assoc ["I" "miss" "you"] 1 "love")
=> ["I" "love" "you"]
晚安啦~(揮手)