摸索 Elm

  1. 1. 選 Elm 的原因
  2. 2. 心得
  3. 3. 一些困擾的地方
    1. 3.0.1. 額外的 library 太少,或沒跟上新的版本
    2. 3.0.2. View 自訂 component 時,語法風格沒法統一
    3. 3.0.3. 沒有 null
    4. 3.0.4. 其他一些晦澀的地方
  • 4. 後話
  • 5. 結論
  • banner

    前陣子在考慮摸索 Elm,剛好在那時候也在找當季蔬果的資料,後來想想,乾脆用這些資料來當作摸索的題材,於是這網站就誕生了,以下來大概講一下感想。

    選 Elm 的原因

    很大一部份其實是逃避現實,由於 JavaScript 的 framework 跟 library 大量出現,而且不僅是前後端,還延伸到桌面軟體、APP 甚至是 IoT 上。以前只是將 ES6 轉成 ES5 的 Babel,現在除了將可能會有的 ECMAScript 語法轉換以外,還可以讓 JS 支援一些不存在的語法(比如 Flow),再配上 webpack 還可以進一步定義更深的語法結構,雖然不是說非得全包全學不可,但五花八門的輪子不斷冒出,當下感覺是非常的吃不消。

    當時摸的是 React,雖然我個人挺喜歡這 library JSX 語法我很討厭,加上圍繞著 React 衍生的各種有的沒的花樣,輕則只是加點功能,重則有如在這之上又加了自創的語法一般,導致整個檔案看起來就像是三四種語言或語法風格的大雜燴,但不得不說,React 生態系真的把 JS 玩得很溜,比如 styled-components 又是一絕,但又要多塞一種風格在裡面我得考慮考慮。

    原本下一個想碰的是 Cycle.js,但後來想想,Redux 跟 Cycle.js 都有跟 Elm 借鑒一些東西,加上繼 Redux 出現之後,Elm 被關注的程度似乎有上升的趨勢,不如就直接學 Elm 看看,而這也是我第一個學的轉 JS 的語言。

    心得

    除了剛開始完全不知道怎麼下手外,整體寫起來的感受還算是不錯的,一開始讓我最欣賞的就是程式的引入方式,免去了引入時要寫 ../../ 之類相對路徑的麻煩。

    1
    2
    -- Components/Header.elm
    module Components.Header exposing (..)
    1
    2
    -- Somewhere else
    import Components.Header exposing (..)

    Pipeline 似乎是大部分函數式語言都會有的東西,不過第一次使用時是覺得也是挺有趣的部份,避免掉小括號連包的情況。在 JS 底下類似鏈式寫法,只是某些地方可能得再自己寫個 prototype 接起來或是直接用 lodash 之類的比較快。

    1
    2
    num = 1
    multiply(4, add(1, num))
    1
    2
    3
    4
    -- Same as
    num
    |> add 1
    |> multiply 4

    Elm 既是一門語言,也是一個 framework,所以建立 HTML 的部份也不會顯得突兀,這部份也是 Cycle.js 參考的地方,跟 JSX 比起來,也比較不會有那種 JS 跟 XML 塞在一起充滿嚴重違和感的感覺。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    div [ class "search-bar" ]
    [ label [ class "label material-icons", for "search" ] [ text "search" ]
    , input
    [ id "search"
    , type_ "search"
    , name "search"
    , placeholder "Search..."
    , onInput (\value -> SearchMsg <| Name value)
    ] []
    ]

    而 Redux 則是參考了 Elm 的事件處理方式,也就是 The Elm Architecture 的部份。

    一些困擾的地方

    額外的 library 太少,或沒跟上新的版本

    這大概是冷門語言最現實的地方,當初想找個線上資料庫之類的服務把當季蔬果的資訊存進去,本來找了 Firebase,但相對應的 elmfire 卻是卡在支援 Elm 0.16 版遲遲未更新。之後想改找 GraphQL 的服務,但 elm-graphql 不管試了幾個服務都沒法接上。由於希望能先把網站做出來,所以後來直接丟 Contentful CMS 用直接 call 網址的方式取資料。

    View 自訂 component 時,語法風格沒法統一

    我在寫 React 時都盡量讓 XML 的區域只出現 XML,而不是中間又插個 JS 搞得更不倫不類,而 Vue 已經把兩個分開,所以不太需要擔心這種事,但 Elm 的一個標籤兩個陣列的寫法我反而很難配合寫出一樣的銜接 component 的方式。

    如果只是單純的資料傳遞還算勉強有方法,但加上事件處理流程後就很難這樣辦了。

    沒有 null

    有些語言回傳空值是沒在用 null 的,取而代之的是用額外的 package(Elm 是取名叫 Result)再包裝一遍,然後再把值取出來。這事已經在 Rust 見試過一次了,雖不討厭但還沒適應這寫法就是。

    其他一些晦澀的地方

    文件有些地方沒有付範例還蠻難看懂的,比如當我想用 Dict.map 這個函式時,描述所寫的:

    1
    2
    3
    4
    map
    : (comparable -> a -> b)
    -> Dict comparable a
    -> Dict comparable b

    我是怎樣也看不明白,後來翻到這篇文章時才知道原來是要這樣子寫:

    1
    Dict.map (\key value -> do something) data

    另外像程式碼報錯的部份,我最常被指出的錯誤是函數的接收或回傳的型態描述不對,而他會很貼心的建議你應該是要寫另外一種,但他建議的照做之後有時又會錯得更厲害,彷彿被愚弄了一樣,尤其 Elm 的型態不是只有 IntStringList 之類常見的型態,還可以自訂其他的型態,再加上 The Elm Architecture 的架構,初學時在多方來往之間,有時一個小地方搞混可能得找老半天才知道真正的問題是什麼,而那個答案也不會是當初 Elm 檢查時所給你的建議。

    其他一些像 main program 的 Program Never Model Msg 這奇怪的描述,到最後是完全不想懂了。

    後話

    老實說,在寫的期間,曾有數度想要推掉用 JS 重寫的衝動,並不是越寫越討厭的關係,而是一方面從 JS 這類語言回頭去學嚴謹的語言會有不少困難,另一方面還是會有「反正到頭來都是轉回去 JS,學這幹麻?」的念頭在。但在寫的過程中,文件的描述以及途中尋找一些 library,期待他至少「堪用」但沒想到是「沒法用」的情況下,也是加深重寫的想法的原因之一。

    最大的收穫大概是對函數式的寫法有更多的經驗,雖然平常寫 js 就會盡量以函數式的方式寫,但不會每個 function 都拆分得乾乾淨淨,離嚴格遵守有很大的距離,在被 Elm 逼著你這樣思考這樣寫之後,對往後寫 js 的程式架構分配也會有很大的幫助。

    至於 Elm 會不會變流行?我覺得不會,畢竟 JS 的生態圈裡不只 framework 跟 library 氾濫,連可以轉成 JS 的語言數量也氾濫無比,隨著 ES6/7 正式上線,以及 ES8 開始規劃支援後,選用非 JS 的語言再轉換這件事就更加沒有必要了,更何況那一票套件也是都要用自己的 webpack loader 做轉換才能動了!

    但如果 WebAssembly 開始正式推行的話,或許會有不一樣的氣象也說不定,我想到時除了為了寫遊戲而使用 WebAssembly 的語言外,像 Elm 這種獨立語言 + framework 的語言也會跟著變多吧!

    至少我不太會想拿來寫第二個網站就是…

    結論

    Always bet on js - by Brendan Eich(JS 之父)。