Skip to main content

Command Palette

Search for a command to run...

淺嚐 Elixir

Published
2 min read

來聊一下最近在唸的新玩具: Elixir。 發音是:「ㄦ利ㄎ洗爾」

Why Elixir

是說去年底 Peepcode 還活著的時候有出過一集 Elixir 的教學。我一直蠻仰慕這個寫出這本厲害的 Craft Rails Applications 的作者 José Valim ,但是這影片一直在 stack 的最底端沒機會去看。( 話說 José 是巴西人,回頭去看影片,一直會聽到小舌音的 "ㄟ赫爾",要仔細聽前後文才發現是 "error"。)

一直到上次 Dave Thomas 路過台灣被 Ruby Taiwan 社群拉來吃熱炒,席間聊到他寫的新書 Programming Elixir 。他說電腦跟手機核心愈來愈多,分散式運算是肯定是未來五年最重要的課題之一,也提到最後出線的也許不是 Elixir ,但是出頭的那個語言必然會有相似的概念 ( 看看 go 那個精美的 goroutine ) 。加上他總是說一年要學一門讓你重新思考的新語言,講的這麼有趣,一頓飯吃完腦也被順利的洗過一輪了。

What is Elixir

2012 才發表的 Elixir 是建在 Erlang Virtual Machine (BEAM) 上的函數式語言。繼承 Erlang 優秀的分散式運算模型 Actor model ,「目標是在 Erlang 生態系裡帶進高生產力及高擴展性的開發過程」。簡單來說就是像 Ruby 的漂亮語法,更一致的操作跟 meta-programming 能力。

Elixir 這個字是萬靈藥的意思。Dave 的新書裡還開了這樣一個玩笑:"Of course, I'm not saying that Elixir is a magic potion (well, technically it is, but you know what I mean)."

Disclaimer: Elixir 當下版本為 0.14.3。最近幾乎每個月都會有更新。雖然已有公司用在正式環境上,但幾乎都是原來就使用 Erlang 的公司才敢這麼做。另外我書也還沒整本看完。 XD


我喜歡的部份

0. Script and compiled

Elixir 有兩種副檔名:exexs。執行 exs 副檔名時,預設會直譯並執行。若是 ex 副檔名,則會編譯成 BEAM binary 後執行。想要手動編譯 exs 檔案也是可以的。

1. 樣式比對 (Pattern matching)

Elixir ( 及 Erlang ) 的等號並不是單純的指派,而是樣式比對。當我們在數學上說 y = x + 1 時,並不是說把 y 指派成 x + 1。而是說當 x 為某值時,y 會依規則 ( 這裡指的是 + 1 ) 比對成另外一個值。

在 Ruby 中,當你寫

a, a, b = [1, 2, 3] # => a 會是 2

因為第二次指派覆蓋了第一次指派。

而在 Elixir 中,則是這樣:

[a, a, b] = [1, 2, 3]
# => ** (MatchError) no match of right hand side value: [1, 2, 3]

[a, a, b] = [1, 1, 3]
# => 因為能成功比對,a 會是 1,b 則是 3

樣式比對在 Elixir 裡用法相當巧妙,例如:

[ head | tail ] = [1, 2, 3, 4, 5]
# =>  head 是 1, tail 是 [2, 3, 4, 5]

以及函式呼叫:

parse_response = fn
  {:ok, value}  -> render(value)
  {:err, msg} -> show_error(msg)
end

parse_response.(response)

會依 response{:ok, something} 或是 {:err, something} 決定執行的方法區塊。

2. List and Recursive

有了上面的樣式比對,就可以寫出非常漂亮的遞迴函式:

defmodule Factorial do
  def calc(0), do: 1
  def calc(val), do: val * calc(val - 1)
end

以及 list 處理函式:

defmodule Sum
  def calc([]), do: 0
  def calc([ head | tail]), do: head + calc(tail)
end

3. Pipe operator

我們常常看到這種程式:

request = generate_request
response = get_response(request)
body = parse_body(response, :html)
html = render(body)

因為若想省去中間那些暫時的變數,就要寫成這樣:

html = render(parse_body(get_response(generate_request), :html))

這看起來更醜,你得要從裡面讀到外面,而且還常常找不到開始讀的點。

Pipe operator |> 可以讓你把回傳值當成下一個函式呼叫的第一個參數。所以上面的例子會寫成:

html = generate_request
       |> get_response
       |> parse_body(:html)
       |> render

當看到上面的寫法之後,我好像看懂了底下這句話:

Functional programming is like a jounery of data transforming.


稿擠,有機會再來寫:

  • The function capture notation
  • Spawn a process
  • pmap
  • Meta-programming with marco
  • Mix and Doctest



What I feel until now:

之前有短暫的摸過 Clojure,也唸了兩章 SICP。不過這幾個週學 Elixir,時不時有種頓悟的感覺。好像又多了解 Functional programming 一點點。更重要的是,這語言到目前為止,讓我獲得非常多的樂趣。

Happy hacking!

More from this blog

聊聊 Elixir 中的 type

最近有幾位朋友分別來問 Elixir 的 type 的問題,想說中文世界好像沒有比較完整的東西,就把知道的東西整理出來。 (目前) Elixir 的 type 能做什麼? tl;dr: 最主要是文件,然後在某種程度下防止錯誤。 我覺得這應該是在研究 Elixir 的 type 時最需要知道的事情了。不像 Haskell 及 F# 這種以型別著稱的 ML 系語言,Elixir / Erlang 本質上是個動態語言,所有與型別有關的標註都會被編譯器忽略。而 Erlang 內建的型別檢查工具 dia...

Oct 18, 20222 min read

Steam 上的程式教學類遊戲

農曆年期間比較有空,玩了一些之前買的遊戲。這次特別試了幾個標榜讓不會寫程式的人學寫程式的遊戲。分享一下試玩的心得。 1. 7 Billion Humans 考慮到劇情的話我最喜歡的是 7 Billion Humans。它用拖拉語法的方式下指令,一開始還蠻好上手的,但是因為只有 goto 那樣的結構,而操作的時候又是一次對所有的 worker 下指令,所以常常要想一下執行後每個人運作的順序。但是介面有正體中文,以「想要體驗一下寫程式大概是怎麼一回事」來說還蠻適合的。 2. while Tru...

Feb 24, 20201 min read

Let's (re)start from here.

最近的時間大半都花在這上面了。 算算應該是第五次弄部落格系統。算一下扣除上古時期用現成的之外,每個系統平均各寫六篇文章,也都撐不過兩年。前幾個分別用了 Refinery CMS -> jekyll -> middleman -> jekyll。想來架系統的總時數應該超過寫文章的時間 XD 而這次用上了 Gatsby + tailwindcss,除了恢復一下 GraphQL 的手感之外,這次還挑戰了不套別人做的版型,自己把類似上一個部落格的 style 刻出來。想說來分享一下這些技術的感想: G...

Jan 11, 20201 min read

Mostly Functional

31 posts

/.(ex|jsx?|rb|hs|rs|py)/, A father, a bookworm, a pluviophile. Co-organizer of http://Elixir.tw. Learning Satir, coaching & mediation.