Elm_(编程语言)

**Elm** 是一個領域特定程式語言，用於聲明式地建立基於 web 瀏覽器的圖形化使用者介面。Elm 是純函數式的，開發它時強調了易用性、效能和健壯性。它宣傳為「實際上沒有執行時間異常」，Elm 編譯器的靜態型別檢查使之成為可能。

## 歷史

Elm 最初由 Evan Czaplicki 在 2012 年作為畢業論文《Elm：用於函數式 GUI 的並行 FRP》而設計的。Elm 的首次發行帶有很多例子和一個線上編輯器，使得易於在 web 瀏覽器中試驗它。Evan 在 2013 年加入 Prezi 從事 Elm 的工作，並在 2016 年轉移到 NoRedInk 作為開源工程師，啟動了 Elm 軟體基金會。

Elm 編譯器的最初實現執行目標為 HTML、CSS 和 JavaScript。核心工具集持續的擴充，現在包括了 REPL、包管理器、時間旅行除錯器和針對 macOS 及 Windows 的安裝器。 Elm 還有一個生態系統，包括社群建立的庫和 Ellie，它是一個進階線上編輯器，允許儲存工作和包含社群庫。

## 特徵

Elm 有一個小集合的語言構造，包括傳統的 if 表達式，let 表達式用於局部狀態，和 case 表達式用於模式匹配。作為函數式語言，它預設的支援匿名函式，函式作為實際參數，和部份應用。它的語意包括不可變的值，無狀態函式，和具有類型推論的靜態型別。Elm 程式通過虛擬的 DOM 呈現 HTML，還可以使用「JavaScript 作為服務」來與其他代碼進行互操作。

### 不可變性

在 Elm 中所有的值都是不可變的，這意味著一個值不能在建立之後修改。Elm 使用永續性資料結構來實現它的 `Array`、`Dict` 和 `Set` 庫。

### 靜態型別

Elm 是靜態型別的。類型標註（annotation）是可選的（由於有類型推論）但強烈鼓勵。標註存在於定義之上的一行（不同於 C 家族語言，這裡的類型和名字是夾雜在一起的）。Elm 使用單一的冒號表達「擁有類型」。

類型包括原始類型如整數和字串，和基本資料結構比如列表、元組和記錄。函式擁有用箭頭寫成的類型，例如 `round : Float -> Int`。客製化類型允許編程者建立客製化類型，以匹配特定問題領域的方式來表示資料。

類型可以推論出其他類型，例如 `List Int`。類型總是首字母大寫；小寫名字是類型變數。例如，`List a` 是未知類型的值的列表。它是空串列和給 `List.length` 的實際參數的類型，對於這個列表的元素而言它是不可知的。有一些特殊類型，編程者建立用來與 Elm 執行時進行互動。例如，`Html Msg` 表示（虛擬）DOM 樹，其事件處理類型 `Msg` 的所有產生訊息。

不再允許任何值是隱含的可空值（比如 JavaScript 的 `undefined` 或空指標），Elm 的標準庫定義了 `Maybe a` 類型。產生或處理一個可選值的代碼不顯式的使用這個類型，而所有其他代碼得到保證聲稱了類型的值是實際上存在的。

Elm 提供有限數目的內建類型類：`number`，它包括 `Int` 和 `Float`，用來利用數值算符比如 `(+)` 或 `(*)`；`comparable`，它包括數值、字元、字串、可比較者的列表和可比較者的元組，用來利用比較算符；和 `appendable`，它包括字串和列表，用來利用 `(++)` 進行串接。Elm 不提供將客製化類型包括入這些類型類，或建立新類型類的機制（參見限制章節）。

### 模組系統

Elm 擁有模組系統來允許使用者將其代碼分解到叫做模組的更小的部份之中。模組可以隱藏實現細節比如幫助函式，並組織有關的代碼在一起。模組為可匯入代碼充當命名空間，比如 `Bitwise.and`。第三方庫（或包）構成自一個或多個模組，並可從 Elm 公共庫中獲得到。所有的庫都採用語意版本號，這是編譯器和其他工具所強制的。就是說，移除一個函式或改變它的類型只能在主要發行中進行。

### 同 HTML、CSS 和 JavaScript 的互操作

Elm 使用叫做埠的抽象來與 JavaScript 通信。它允許值流入和流出 Elm 程式，確使了在 Elm 和 JavaScript 之間的通信。

Elm 有一個叫做 elm/html 的庫，編程者可以用來在 Elm 內書寫 HTML 和 CSS。它使用虛擬 DOM 方式來使更新有效率。

### 後端

Elm 官方上不支援伺服器端開發。核心開發團隊不將它作為主要目標考慮，並且偏好聚焦於在增進前端開發體驗上的開發。儘管如此，有一些獨立的計劃，它們嘗試探索將 Elm 用於後端的可能性。這些計劃主要系附於 Elm 版本 0.18.0，因為更新的版本不支援「原生」代碼和其他可利用特徵。有兩個嘗試將 Elm 用在 BEAM（Erlang 虛擬機器）之上。其中一個計劃直接在這個環境上執行 Elm，而另一個計劃把它編譯成 Elixir。還有一個嘗試通過 Node.js 下部結構為 Elm 建立後端框架。這些計劃都沒有準備好用於生產。

## Elm 架構

Elm 架構是建造互動式 web 應用的模式。Elm 應用本質上以這種方式來構造，但是其他專案可能發現這個概念很有用。

Elm 程式總是分解成三個部份：

* 模型：這個應用的狀態，
* 視圖：一個把模型轉變成 HTML 的函式，
* 更新：一個基於訊息更新模型的函式。

這些是 Elm 架構的核心。

例如，想像顯示一個數值和在按下時增加這個數值的一個按鈕的一個應用。在這種情況下，所有我們需要儲存的是一個數值，所以我們的模型可以簡單的就是 `type alias Model = Int`。`view` 函式將用 `Html` 庫來定義並顯示這個數值和按鈕。為了讓這個數值被更新，我們需要能夠向 `update` 函式傳送訊息，這是通過客製化類型比如 `type Msg = Increase` 來完成的。 `Increase` 值被附著於在 `view` 函式內定義的按鈕，使得在使用者點擊這個按鈕的時候，`Increase` 被傳遞到 `update` 函式之上，它可以通過增加這個數值來更新這個模型。

在 Elm 架構中，傳送訊息至 `update` 是改變狀態的唯一方式。在更加複雜的應用中，訊息可以來自各種來源：使用者互動，模型初始化，來自 `update` 的內部呼叫，訂閱的外部事件（窗口改變大小、系統時鐘、JavaScript 互操作等等）和 URL 變更及請求。

## 限制

Elm 不支援高種類多型，這是同為函數式的語言 Haskell 和 PureScript 所提供的，Elm 還不支援建立類型類。

這意味著，例如 Elm 沒有跨越多種資料結構如 `List` 和 `Set` 的通用的 `map` 函式。在 Elm 中，這種函式典型的要限定上它們的模組名字來呼叫，例如呼叫 `List.map` 和 `Set.map`。在 Haskell 或 PureScript 中，只有一個函式 `map`。自從 2015 年這就是在 Czaplicki 的粗略路線圖上的一個周知的特徵要求。

另一個缺陷是在中到大型專案中有大量的樣板代碼，如《Elm in Action》作者在他們的單一頁面應用例子中所展示的那樣，具有幾乎同樣的片段被重複於更新、視圖、訂閱、路由解析和建造函式之中。

## 樣例代碼

下面的例子代碼通過注釋展示了 Elm 的基本特徵：

## 參見

* PureScript：一個強型別的、純函數式的編譯成 JavaScript 的程式語言。
* Reason：OCaml 的語法擴充和工具鏈，也可以轉譯成 JavaScript。
* 函數式回應式編程

## 參照

## 外部連結

* 官方網站
* Awesome Elm. [2021-03-02]. （原始內容存檔於 2021-01-17）.