Elm 快速指南



Elm - 簡介

Elm 是一種函數語言程式設計語言。它由 Evan Czaplicki 於 2012 年設計。

Elm 特別用於設計 Web 應用程式的前端。

Elm 編譯成 JavaScript 並在瀏覽器中執行。它速度快、可測試、可維護,並且沒有執行時異常。

Elm 程式設計平臺的一些實際應用包括:

  • 遊戲
  • 圖形
  • 單頁面應用程式

為什麼選擇 Elm

Elm 消除了前端開發人員面臨的大多數常見問題。這包括:

沒有執行時異常

Elm 是一種靜態型別語言。所有可能的錯誤都在編譯時進行驗證和更正。這使得它能夠沒有執行時異常。

開發人員友好的錯誤訊息

與其他程式語言不同,Elm 的編譯器旨在在編譯時提供非常具體且開發人員友好的錯誤訊息。錯誤訊息還包括提示,例如指向推薦的設計文件的連結。

易於測試

每個 Elm 函式都可以獨立於所有其他函式進行測試。這使得用 Elm 編寫的程式易於測試。

自動語義版本控制

Elm 強制對包進行自動語義版本控制。這確保補丁更改不會使正在執行的應用程式崩潰。

可重用程式碼

與 JavaScript、Python 或 TypeScript 中的函式相比,Elm 函式本質上易於重用。

Elm - 環境設定

本章討論在 Windows、Mac 和 Linux 平臺上安裝 Elm 的步驟。

本地環境設定

請考慮以下步驟在您的本地環境中安裝 Elm。

步驟 1 - 安裝 node

由於 elm 編譯成 JavaScript,目標機器應安裝 node。有關設定 nodenpm 的步驟,請參閱 TutorialsPoint NodeJS 課程

Node 設定。

步驟 2 - 安裝 elm

在終端上執行以下命令以安裝 elm。請注意,在撰寫本課程時,elm 的穩定版本為 0.18。

npm install -g elm@0.18
Install elm

安裝後,執行以下命令以驗證 Elm 的版本。

C:\Users\dell>elm --version
0.18.0

步驟 2 - 安裝編輯器

此處使用的開發環境是 Visual Studio Code(Windows 平臺)。

Visual Studio Code 是來自 Visual Studio 的開源 IDE。它適用於 Mac OS X、Linux 和 Windows 平臺。VSCode 可在以下網址獲取

https://vscode.com.tw/。

在 Windows 上安裝

在本節中,我們將討論在 Windows 上安裝 Elm 的步驟。

下載 https://vscode.com.tw/。 用於 Windows。

雙擊 VSCodeSetup.exe 啟動安裝過程。這隻需要一分鐘。

VSCodeSetup

您可以透過右鍵單擊檔案 → 在命令提示符中開啟直接跳轉到檔案的路徑。同樣,“在資源管理器中顯示”選項會在檔案資源管理器中顯示檔案。

Reveal Explorer

在 Mac OS X 上安裝

Visual Studio Code 的 Mac OS X 特定安裝指南可在 VSCode 安裝-MAC 找到。

在 Linux 上安裝

Visual Studio Code 的 Linux 特定安裝指南可在 VSCode 安裝-Linux 找到。

步驟 4 - 安裝 elm 擴充套件

如下所示在 VSCode 中安裝 elm 擴充套件。

Installation Linux

Elm REPL

REPL 代表讀取-求值-列印-迴圈。它表示一個計算機環境,例如 Windows 控制檯或 Unix/Linux shell,使用者在其中輸入命令,系統以互動模式響應輸出。

Elm 帶有一個 REPL 環境。它執行以下任務:

  • 讀取 - 讀取使用者的輸入,將輸入解析為 elm 資料結構,並存儲在記憶體中。

  • 求值 - 獲取並評估資料結構。

  • 列印 - 列印結果。

  • 迴圈 - 迴圈執行上述命令,直到使用者退出。使用命令 :exit 退出 REPL 並返回到終端。

下面是一個在 REPL 中新增兩個數字的簡單示例:

開啟 VSCode 終端並鍵入命令 elm REPL。

REPL 終端等待使用者輸入一些內容。輸入以下表達式 10 + 20。REPL 環境處理輸入如下所示:

  • 從使用者處讀取數字 10 和 20。

  • 使用 + 運算子進行求值。

  • 將結果列印為 30。

  • 迴圈等待下一個使用者輸入。在這裡我們退出迴圈。

Elm REPL

Elm - 基本語法

本章討論如何在 elm 中編寫一個簡單的程式。

步驟 1 - 在 VSCode 中建立一個目錄 HelloApp

現在,在此目錄中建立一個檔案 - Hello.elm

Create directory

上圖顯示了專案資料夾 HelloApp 和在 VSCode 中開啟的終端。

步驟 2 - 安裝必要的 elm 包

elm 中的包管理器是 elm-package。安裝 elm-lang/html 包。此包將幫助我們在瀏覽器中顯示 elm 程式碼的輸出。

透過右鍵單擊檔案 → 在 VSCode 中開啟命令提示符來跳轉到 HelloApp 專案資料夾。

在終端視窗中執行以下命令:

C:\Users\dell\Elm\HelloApp> elm-package install elm-lang/html

安裝包後,以下檔案/資料夾將新增到專案目錄中。

  • elm-package.json(檔案),儲存專案元資料
  • elm-stuff(資料夾),儲存外部包

包成功安裝後,將顯示以下訊息。

package installed

步驟 3 - 將以下程式碼新增到 Hello.elm 檔案中

-- importing Html module and the function text
import Html exposing (text)

-- create main method
main =
-- invoke text function
text "Hello Elm from TutorialsPoint"

上述程式將在瀏覽器中顯示字串訊息 Hello Elm from TutorialsPoint

為此,我們需要在 Html 模組中匯入函式 text。text 函式用於在瀏覽器中列印任何字串值。main 方法是程式的入口點。main 方法呼叫 text 函式並將字串值傳遞給它。

步驟 4 - 編譯專案

在 VSCode 終端視窗中執行以下命令。

elm make Hello.elm

上述命令的輸出如下所示:

//update path to the proj folder in the command elm make
C:\Users\dell\elm\HelloApp>elm make Hello.elm
Success! Compiled 38 modules.
Successfully generated index.html

上述命令將生成一個 index.html 檔案。elm 編譯器將 .elm 檔案轉換為 JavaScript 並將其嵌入到 index.html 檔案中。

步驟 5 - 在瀏覽器中開啟 index.html

在任何瀏覽器中開啟 index.html 檔案。輸出將如下所示:

Open browser

Elm 中的註釋

註釋是提高程式可讀性的一種方法。註釋可用於包含有關程式的其他資訊,例如程式碼作者、有關函式構造的提示等。註釋被編譯器忽略。

Elm 支援以下型別的註釋:

  • 單行註釋 (--) - -- 和行尾之間的任何文字都被視為註釋。

  • 多行註釋 ({- -}) - 這些註釋可以跨越多行。

圖示

-- this is single line comment

{- This is a
   Multi-line comment
-}

行和縮排

Elm 沒有提供大括號來指示函式定義或流程控制的程式碼塊。程式碼塊由行縮排表示,並且嚴格執行。塊中的所有語句必須縮排相同的量。例如:

module ModuleIf exposing (..)
x = 0

function1 =
   if x > 5 then
      "x is greater"
   else
      "x is small"

但是,以下塊會生成錯誤:

-- Create file ModuleIf.elm
module ModuleIf exposing (..)
x = 0

function1 =
   if x > 5 then
      "x is greater"
         else --Error:else indentation not at same level of if statement
      "x is small"

因此,在 Elm 中,所有以相同空格數縮排的連續行將構成一個塊。

C:\Users\admin>elm repl
---- elm-repl 0.18.0 -----------------------------------------------------------
   :help for help, :exit to exit, more at 
   <https://github.com/elm-lang/elm-repl>
   ---------------------------------------
   -----------------------------------------

> import ModuleIf exposing(..) -- importing module from ModuleIf.elm file
>function1 -- executing function from module
-- SYNTAX PROBLEM ---------------------------------------------------

I need whitespace, but got stuck on what looks like a new declaration. 
You are either missing some stuff in the declaration above or just need to add some spaces here:
7| else
   ^
I am looking for one of the following things:

   whitespace

Elm - 資料型別

型別系統表示語言支援的不同型別的值。型別系統在程式儲存或操作提供的值之前檢查其有效性。這確保程式碼按預期執行。型別系統還允許更豐富的程式碼提示和自動文件。

Elm 是一種靜態型別語言。Elm 的型別類似於其他語言中的型別。

數字

number 資料型別表示數值。Elm 型別系統支援以下數值型別:

序號 型別 示例
1 number - 儲存任何數字 7 是 number 型別
2 Float - 儲存小數值 7/2 得到 3.5 結果為 Float
3 Int - 儲存非小數值 7//2 得到 3 結果為 Int

number 型別可容納小數和非小數值。開啟 elm REPL 並嘗試以下示例:

C:\Users\admin>elm repl
---- elm-repl 0.18.0 
---------------------------------------------
--------------
:help for help, :exit to exit, more at <https://github.com/elm-lang/elm-repl>
------------------------------------------
--------------------------------------
> 7
7 : number
> 7/2
3.5 : Float
> 7//2
3 : Int
>

字串和字元

String 資料型別用於表示字元序列。Char 資料型別用於表示單個字元。String 值定義在雙引號 " 內,Char 值包含在單引號 ' 內。

序號 型別 示例
1 String - 儲存字元序列 "TutorialsPoint"
2 Char - 儲存小數值 'T'

開啟 elm REPL 並嘗試以下示例:

C:\Users\admin>elm repl
---- elm-repl 0.18.0 ---------------------------------------
--------------------
:help for help, :exit to exit, more at <https://github.com/elm-lang/elm-repl>
--------------------------------------
------------------------------------------
> "TutorialsPoint"
"TutorialsPoint" : String
> 'T'
'T' : Char

布林值

Elm 中的 Bool 資料型別僅支援兩個值 - True 和 False。關鍵字 Bool 用於表示布林值。

序號 型別 示例
1 Bool - 儲存值 True 或 False 1==1 返回 True

開啟 elm REPL 並嘗試以下示例:

C:\Users\dell\elm>elm repl
---- elm-repl 0.18.0 -----------------------------------
------------------------
:help for help, :exit to exit, more at <https://github.com/elm-lang/elm-repl>
----------------------------------------
----------------------------------------
> True
True : Bool
> False
False : Bool
> 1==1
True : Bool
> 1==2
False : Bool
> 1 /= 2 -- not equal
True : Bool
> not True
False : Bool
> not False
True : Bool

自定義型別

Elm 支援建立使用者定義型別。例如,考慮一個支付應用程式。該應用程式需要儲存不同的支付方式 - 信用卡、簽帳金融卡和網上銀行。這可以透過定義自定義型別並將其值限制為三種可接受的支付方式來實現。

以下示例顯示瞭如何建立自定義型別。

> type PaymentMode = CreditCard|NetBanking|DebitCard
> payment1 = CreditCard
CreditCard : Repl.PaymentMode
> payment2 = DebitCard
DebitCard : Repl.PaymentMode
> payment3 = UPI
-- NAMING ERROR ---------------------------------------------- repl-temp-000.elm

Cannot find variable `UPI`

7| payment3 = UPI

在上面的示例中,我們建立了一個 PaymentMode 自定義型別。變數 payment1 和 payment2 分配給 PaymentMode 值。如果分配給變數的值與 PaymentMode 型別定義的任何值都不匹配,則應用程式將丟擲語法錯誤。

結構化資料型別

結構化資料型別可用於以結構化格式儲存多個值。Elm 支援以下結構化資料型別:

  • 元組
  • 列表
  • 記錄
  • 記錄

這些將在後續章節中詳細討論。

Elm - 變數

根據定義,變數是“記憶體中命名的空間”,用於儲存值。換句話說,它充當程式中值的容器。變數幫助程式儲存和操作值。

Elm 中的變數與特定資料型別相關聯。資料型別確定變數記憶體的大小和佈局、可以儲存在該記憶體中的值的範圍以及可以對變數執行的操作集。

變數命名規則

在本節中,我們將瞭解變數命名規則。

  • 變數名可以由字母、數字和下劃線字元組成。
  • 變數名不能以數字開頭。它必須以字母或下劃線開頭。
  • 大小寫字母是不同的,因為 Elm 區分大小寫。

在 Elm 中宣告變數

在 Elm 中宣告變數的型別語法如下所示:

語法 1

variable_name:data_type = value

“ : ” 語法(稱為型別註釋)用於將變數與資料型別關聯。

語法 2

variable_name = value-- no type specified

在 Elm 中宣告變數時,資料型別是可選的。在這種情況下,變數的資料型別是從分配給它的值推斷出來的。

圖示

此示例使用 VSCode 編輯器編寫 Elm 程式,並使用 Elm REPL 執行它。

步驟 1 - 建立一個專案資料夾 - VariablesApp。在專案資料夾中建立一個 Variables.elm 檔案。

將以下內容新增到檔案中。

module Variables exposing (..) //Define a module and expose all contents in the module
message:String -- type annotation
message = "Variables can have types in Elm"

程式定義了一個名為 Variables 的模組。模組的名稱必須與 Elm 程式檔案相同。(..) 語法用於公開模組中的所有元件。

程式聲明瞭一個型別為 String 的變數 message。

Illustration

步驟 2 - 執行程式。

  • 在 VSCode 終端中鍵入以下命令以開啟 Elm REPL。
elm repl
  • 在 REPL 終端中執行以下 Elm 語句。
> import Variables exposing (..) --imports all components from the Variables module
> message --Reads value in the message varaible and prints it to the REPL 
"Variables can have types in Elm":String
>

圖示

使用 Elm REPL 嘗試以下示例。

C:\Users\dell\elm>elm repl
---- elm-repl 0.18.0 ---------------------------------------
--------------------
:help for help, :exit to exit, more at <https://github.com/elm-lang/elm-repl>
-------------------------------------
------------------------------------------
> company = "TutorialsPoint"
"TutorialsPoint" : String
> location = "Hyderabad"
"Hyderabad" : String
> rating = 4.5
4.5 : Float

這裡,變數 company 和 location 是 String 變數,rating 是 Float 變數。

Elm REPL 不支援變數的型別註釋。如果在宣告變數時包含資料型別,則以下示例將引發錯誤。

C:\Users\dell\elm>elm repl
---- elm-repl 0.18.0 -----------------------------------------
------------------
:help for help, :exit to exit, more at <https://github.com/elm-lang/elm-repl>
----------------------------------------
----------------------------------------
> message:String
-- SYNTAX PROBLEM -------------------------------------------- repl-temp-000.elm

A single colon is for type annotations. Maybe you want :: instead? Or maybe you
are defining a type annotation, but there is whitespace before it?

3| message:String
^

Maybe <http://elm-lang.org/docs/syntax> can help you figure it out.

要在使用 Elm REPL 時插入換行符,請使用 \ 語法,如下所示 -

C:\Users\dell\elm>elm repl
---- elm-repl 0.18.0 --------------------------------------
---------------------
:help for help, :exit to exit, more at <https://github.com/elm-lang/elm-repl>
------------------------------------------
--------------------------------------
> company \ -- firstLine
| = "TutorialsPoint" -- secondLine
"TutorialsPoint" : String

Elm - 運算子

運算子定義了一些將在資料上執行的函式。運算子作用的值稱為運算元。考慮以下表達式

7 + 5 = 12

這裡,值 7、5 和 12 是運算元,而 + 和 = 是運算子。

Elm 中的主要運算子可以分類為 -

  • 算術運算子
  • 關係運算符
  • 邏輯運算子

算術運算子

假設變數 a 和 b 中的值分別為 7 和 2。

顯示示例

序號 運算子 描述 示例
1 +(加法) 返回運算元的和 a+b 為 9
2 -(減法) 返回值的差 a-b 為 5
3 *(乘法) 返回值的積 a*b 為 14
4 /(浮點數除法) 執行除法運算並返回浮點數商 a / b 為 3.5
5 //(整數除法) 執行除法運算並返回整數商 a // b 為 3
6 %(模) 執行除法運算並返回餘數 a % b 為 1

關係運算符

關係運算符測試或定義兩個實體之間關係的種類。這些運算子用於比較兩個或多個值。關係運算符返回布林值,即 true 或 false。

假設 a 的值為 10,b 的值為 20。

顯示示例

序號 運算子 描述 示例
1 > 大於 (a > b) 為 False
2 < 小於 (a < b) 為 True
3 >= 大於或等於 (a >= b) 為 False
4 <= 小於或等於 (a <= b) 為 True
5 == 相等 (a == b) 為 false
6 != 不相等 (a != b) 為 True

可比較型別

比較運算子(如 >= 或 <)適用於可比較型別。這些定義為數字、字元、字串和列表、元組。運算子兩側的可比較型別必須相同。

序號 可比較型別 示例
1 數字 7>2 返回 True
2 字元 'a' =='b' 返回 False
3 字串 "hello" =="hello" 返回 True
4 元組 (1,"One")==(1,"One") 返回 True
5 列表 [1,2]==[1,2] 返回 True

開啟 Elm REPL 並嘗試以下示例 -

C:\Users\admin>elm repl
---- elm-repl 0.18.0 -----------------------------------------------------------
:help for help, :exit to exit, more at <https://github.com/elm-lang/elm-repl>
--------------------------------------------------------------------------------
> 7>2
True : Bool
> 7.0>2
True : Bool
> 7.0<2.0
False : Bool
> 'a' > 'b'
False : Bool
> 'a' < 'b'
True : Bool
> "a" < "b"
True : Bool
> (1,2) > (2,3)
False : Bool
> ['1','3'] < ['2','1']
True : Bool
>

邏輯運算子

邏輯運算子用於組合兩個或多個條件。邏輯運算子也返回布林值。

顯示示例

序號 運算子 描述 示例
1 && 只有當指定的所有表示式都返回 true 時,運算子才返回 true (10>5) && (20>5) 返回 True
2 || 如果指定表示式中至少有一個返回 true,則運算子返回 true (10 < 5) || (20 >5) 返回 True
3 運算子返回表示式的結果的反值。例如:!(>5) 返回 false。 not (10 < 5) 返回 True
4 異或 只有當且僅當一個輸入返回 true 時,運算子才返回 true。如果兩個表示式都返回 true,則運算子返回 false。 xor (10 > 5 ) (20 > 5) 返回 false

Elm - 決策

決策結構要求程式設計師指定一個或多個要由程式評估或測試的條件,以及如果條件確定為 true 則要執行的語句或語句,以及可選地,如果條件確定為 false 則要執行的其他語句。

下面顯示了大多數程式語言中常見的典型決策結構的通用形式

Decision-making

決策結構在執行指令之前評估條件。Elm 中的決策結構分類如下 -

序號 語句 描述
1 if...then...else 語句 if 語句由一個布林表示式後跟 then 組成,如果表示式返回 true 則執行,否則執行 else,如果表示式返回 false 則執行。
2 巢狀 if 語句 您可以在另一個 if 內部使用一個 if...then...else。
3 case 語句 將變數的值與值列表進行比較。

if...then...else 語句

if…then 結構在執行程式碼塊之前評估條件。如果布林表示式計算結果為 true,則將執行 then 語句內部的程式碼塊。如果布林表示式計算結果為 false,則將執行 else 語句內部的程式碼塊。

與其他程式語言不同,在 Elm 中我們必須提供 else 分支。否則,Elm 將丟擲錯誤。

語法

if boolean_expression then statement1_ifTrue else statement2_ifFalse

圖示

在 REPL 終端中嘗試以下示例。

> if 10>5 then "10 is bigger" else "10 is small"
"10 is bigger" : String

巢狀 If

巢狀 if 語句可用於測試多個條件。巢狀 if 語句的語法如下所示 -

if boolean_expression1 then statement1_ifTrue else if boolean_expression2 then statement2_ifTrue else statement3_ifFalse

圖示

在 Elm REPL 中嘗試以下示例 -

> score=80
80 : number
> if score>=80 then "Outstanding" else if score > = 70 then "good" else "average"
"Outstanding" : String

Case 語句

case 語句可用於簡化 if then else 語句。case 語句的語法如下所示 -

case variable_name of
   constant1 -> Return_some_value
   constant2 -> Return_some_value
   _ -> Return_some_value if none of the above values match

case 語句檢查變數的值是否與預定義的一組常量匹配,並返回相應的值。請注意,每個 case 返回的值必須是相同型別。如果變數的值與任何給定的常量都不匹配,則控制權將傳遞給 * default *(用 //_ 表示)並返回相應的值。

圖示

在 Elm REPL 中嘗試以下示例 -

> n = 10
10 : number
> case n of \
| 0 -> "n is Zero" \
| _ -> "n is not Zero"
"n is not Zero" : String

上面的程式碼片段檢查 n 的值是否為零。控制權傳遞給 default,它返回字串“n is not Zero”。

Elm - 迴圈

Elm 是一種函數語言程式設計語言。Elm 使用遞迴的概念作為傳統迴圈結構的替代方案。

本章討論遞迴的概念。

遞迴

某些計算機程式語言允許模組或函式呼叫自身。此技術稱為遞迴。

圖示

在此程式中,我們將瞭解如何使用遞迴將 hello 顯示五次。

步驟 1 - 建立一個檔案 Loop.elm

建立一個名為 Loop 的模組並定義一個函式 sayHello。函式 sayHello 以整數作為輸入並返回字串值。

module Loop exposing(..)
//function signature
sayHello:Int ->String
//function implementation
sayHello n =
   case n of
   1 -> "Hello:1 "
   _ -> "Hello:" ++ toString (n) ++ " " ++ sayHello(n-1)

函式 sayHello 檢查傳遞的引數是否為 1。如果引數為 1,則函式將返回,否則它將建立一個字串 Hello 並呼叫同一個函式。

步驟 2 - 從 REPL 呼叫 sayHello

從當前專案資料夾(Loop.elm 檔案的位置)開啟 Elm REPL。

//import the module Loop
> import Loop exposing(..)
//invoke the sayHello function with parameter value as 5
> sayHello 5
"Hello:5 Hello:4 Hello:3 Hello:2 Hello:1 Hello:0 " : String
>
module Loop

圖示

以下示例使用遞迴列印 n 個數字的總和。

> sumOfNos n =\
| if n==0 then 0 \
| else (n) + sumOfNos (n-1)
<function> : number -> number1

在 Elm REPL 中,我們建立了一個名為 sumOfNos 的函式,它接受一個輸入數字並將 0 到該數字的所有數字求和。

例如,如果我們傳遞輸入為 5,它將計算 1+2+3+4+5 的和,結果為 15

> ssumOfNos 5
15 : number

程式的輸出如上所示。

Elm - 函式

函式是 Elm 程式的基本構建塊。函式是一組執行特定任務的語句。

函式將程式組織成邏輯程式碼塊。定義後,可以呼叫函式來訪問程式碼。這使得程式碼可重用。此外,函式使程式程式碼易於閱讀和維護。

使用函式的步驟

使用函式有三個步驟 -

函式宣告

函式宣告告訴編譯器函式的名稱、返回型別和引數。宣告函式的語法如下所示 -

fn_name:data_type_of_the_parameters ->return_type

函式宣告指定以下內容 -

  • 函式的名稱。

  • 引數的資料型別。這是可選的,因為函式可能有也可能沒有引數。

  • 函式將返回的值的資料型別。Elm 中的函式必須始終返回值,因為 Elm 是一種函數語言程式設計語言。與其他程式語言中的函式不同,Elm 函式不使用 return 關鍵字返回值。

函式定義或函式實現

函式定義提供了函式的實際主體。函式定義指定如何完成特定任務。定義函式的語法如下所示 -

fn_name parameter1 parameter2 = statements

呼叫或呼叫函式

必須呼叫函式才能執行它。呼叫函式的語法如下所示 -

fn_name parameter1 parameter2

圖示

以下程式碼定義了一個名為 greet 的函式。該函式返回字串“Hello”。

> greet = \
| if True then \
| "Hello" \
| else \
| "GoodBye"
"Hello" : String
> greet
"Hello" : String

引數化函式

引數是將值傳遞給函式的一種機制。引數的值在函式呼叫時傳遞給函式。

插圖 1

以下示例定義了一個名為 fn_add 的函式。該函式接受兩個數字作為引數並返回它們的和。在 Elm REPL 中嘗試以下操作 -

> fn_add x y = x+y
<function> : number -> number -> number
> fn_add 10 20
30 : number

插圖 2

以下示例定義了一個名為 sayHello 的函式。sayHello 函式接受並返回一個 String 值作為引數並返回一個 String。

> sayHello name = "Hello "++ name
<function> : String -> String
> sayHello "Tutorialspoint"
"Hello Tutorialspoint" : String
>

管道運算子

要理解管道運算子 |>,讓我們考慮一個示例,其中我們有一個包含不同字串 ["a","b","c"] 的列表。現在我們需要一個用 - 分隔的單個字串

以下示例顯示瞭如何使用 String.join 來實現這一點

> String.join "-" ["a","b","c","d","e","f"]
"a-b-c-d-e-f" : String

可以使用管道運算子 |> 執行相同的操作。管道運算子可用於連結多個函式呼叫。

> ["a","b","c","d","e","f"] |> String.join "-"
"a-b-c-d-e-f" : String
> ["a","b","c","d","e","f"] |> List.reverse |> String.join "-"
"f-e-d-c-b-a" : String

在第一個示例中,我們將列表連結到 join 方法。在第二種情況下,相同的列表被傳遞給 reverse 函式,然後傳遞給 join。因此,列表以反向顯示並連線。

Elm - 字串

一系列 Unicode 字元稱為字串。在 Elm 中,字串用 "" 雙引號 括起來。字串是一塊文字,如下所示。

> "TutorialsPoint"
"TutorialsPoint" : String
> location = "Hyderabad" --variable
"Hyderabad" : String
> location
"Hyderabad" : String
>

字串函式

下面給出了一些可用於查詢或操作字串值的常用函式。使用 REPL 嘗試以下示例。

序號 方法 描述
1 isEmpty : String -> Bool 檢查字串是否為空
2 reverse : String -> String 反轉輸入字串
3 length : String -> Int 返回整數長度
4 append :String -> String -> String 追加兩個字串並返回一個新字串
5 append :String -> Sconcat : List String -> String 追加字串列表並返回一個新字串
6 split : String -> String -> List String 使用給定的分隔符分割輸入字串,返回一個字串列表
7 slice : Int -> Int -> String -> String 給定起始、結束索引和輸入字串,返回子字串
8 contains : String -> String -> Bool 如果第二個字串包含第一個字串,則返回 true
9 toInt : String -> Result.Result String Int 將字串解析為整數
10 toInt : String -> Result.Result String Int 將字串解析為整數
11 toFloat : String -> Result.Result String Float 將字串解析為浮點數
12 fromChar : Char -> String 根據給定的字元建立一個字串。
13 toList : String -> List Char 將字串轉換為字元列表
14 fromList : List Char -> String 將字元列表轉換為字串
15 toUpper : String -> String 將輸入字串轉換為大寫
16 trim : String -> String 去除字串兩側的空格。
17 filter : (Char -> Bool) -> String -> String 從輸入字串中過濾字元集
18 map : (Char -> Char) -> String -> String 轉換輸入字串中的每個字元

isEmpty

此函式可用於確定字串是否為空。如果提供的字串為空,則此函式返回 True。

語法

String.isEmpty String_value

要在 elm REPL 中檢查函式的簽名,請鍵入以下內容:

> String.isEmpty
<function> : String -> Bool

函式的簽名顯示 Bool 作為返回型別,輸入型別為 String:

圖示

> String.isEmpty ""
True : Bool
> String.isEmpty "Tutorialspoint"
False : Bool
> location = "Hyderabad"
"Hyderabad" : String
> String.isEmpty location
False : Bool

reverse

此函式反轉字串。

語法

String.reverse String_value

要在 elm REPL 中檢查函式的簽名,請鍵入以下內容:

> String.reverse
<function> : String -> String

函式的簽名顯示 String 作為返回型別,輸入型別為 String:

圖示

> String.reverse "TutorialsPoint"
"tnioPslairotuT" : String

length

此函式返回字串的長度。

語法

String.length String_value

要在 elm REPL 中檢查函式的簽名,請鍵入以下內容:

> String.length
<function-> : String -> Int

函式的簽名顯示 Int 作為返回型別,輸入型別為 String。

圖示

> String.length "Mohtashim"
9 : Int

append

此函式透過追加兩個字串返回一個新字串。

語法

String.append String_value1 String_value2

要在 elm REPL 中檢查函式的簽名,請鍵入以下內容:

> String.append
<function-> : String -> String -> String

簽名的顯示有兩個 String 輸入引數和一個 String 輸出引數

圖示

> String.append "Tutorials" "Point"
TutorialsPoint : String

concat

此函式透過將多個字串連線成一個返回一個新字串。

語法

String.concat [String1,String2,String3]

要在 elm REPL 中檢查函式的簽名,請鍵入以下內容:

> String.concat
<function> : List String -> String

簽名的顯示一個 String 列表輸入引數和 String 返回型別

圖示

> String.concat ["Hello","Tutorials","Point"]
HelloTutorialsPoint : String

split

此函式使用給定的分隔符拆分字串。

語法

String.split string_seperator String_value

要在 elm REPL 中檢查函式的簽名,請鍵入以下內容:

> String.split
<function> : String -> String -> List String

簽名的顯示兩個輸入 String 引數,輸出為字串型別列表。

圖示

> String.split "," "Hello,Tutorials,Point"
["Hello","Tutorials","Point"] : List String

slice

此函式根據起始和結束索引返回子字串。負索引從列表末尾開始獲取。索引值從零開始。

語法

String.slice start_index end_index String_value

要在 elm REPL 中檢查函式的簽名,請鍵入以下內容:

> String.slice
<function> : Int -> Int -> String -> String

簽名的顯示三個輸入引數和一個返回型別。

圖示

> String.slice 0 13 "TutorialsPoint"
"TutorialsPoin" : String

contains

如果第二個字串包含第一個字串,則此函式返回 True。

語法

String.contains string1 string2

要在 elm REPL 中檢查函式的簽名,請鍵入以下內容:

> String.contains
<function> : String -> String -> Bool

簽名的顯示 bool 返回型別和兩個輸入引數

圖示

> String.contains "Point" "TutorialsPoint"
True : Bool

toInt

此函式將字串轉換為整數。

語法

String.toInt string_value

要在 elm REPL 中檢查函式的簽名,請鍵入以下內容:

> String.toInt
<function> : String -> Result.Result String Int

由於 toInt 可能返回錯誤,因此返回型別為 Result,即 String 或 Int。

圖示

> String.toInt "20"
Ok 20 : Result.Result String Int
> String.toInt "abc"
Err "could not convert string 'abc' to an Int" : Result.Result String Int

toFloat

此函式將字串轉換為浮點數。

語法

String.toFloat string_value

要在 elm REPL 中檢查函式的簽名,請鍵入以下內容:

> String.toFloat
<function> : String -> Result.Result String Float

由於 toFloat 可能返回錯誤,因此返回型別為 Result,即 String 或 Float。

圖示

> String.toFloat "20.50"
Ok 20.5 : Result.Result String Float
> String.toFloat "abc"
Err "could not convert string 'abc' to a Float" : Result.Result String Float

fromChar

此函式根據給定的字元建立一個字串。

語法

String.fromChar character_value

要檢查函式的簽名,請在 elm REPL 中鍵入以下內容:

> String.fromChar
<function> : Char -> String

簽名顯示 String 作為返回型別,輸入為 Char 型別

圖示

> String.fromChar 'c'
"c" : String

toList

此函式將字串轉換為字元列表。

語法

String.toList string_value

要在 elm REPL 中檢查函式的簽名,請鍵入以下內容:

> String.toList
<function> : String -> List Char

簽名顯示函式返回字元列表,並以字串作為輸入。

圖示

> String.toList "tutorialspoint"
['t','u','t','o','r','i','a','l','s','p','o','i','n','t'] : List Char

fromList

此函式將字元列表轉換為字串。

語法

String.fromList list_of_characters

要在 elm REPL 中檢查函式的簽名,請鍵入以下內容:

> String.fromList
<function> : List Char -> String

簽名顯示函式返回字元列表,並以字串作為輸入。

圖示

> String.fromList ['h','e','l','l','o']
"hello" : String

toUpper

此函式將字串轉換為全部大寫。

語法

String.toUpper String_value

要在 elm REPL 中檢查函式的簽名,請鍵入以下內容:

> String.toUpper
<function> : String -> String

圖示

> String.toUpper "hello"
"HELLO" : String

toLower

此函式將字串轉換為全部小寫。

語法

String.toLower String_value

要在 elm REPL 中檢查函式的簽名,請鍵入以下內容:

> String.toLower
<function> : String -> String

圖示

> String.toLower "AbCd"
"abcd" : String

trim

此函式去除字串兩側的空格。

語法

String.trim String_value

要在 elm REPL 中檢查函式的簽名,請鍵入以下內容:

> String.trim
<function> : String -> String

圖示

> String.trim "tutorialspoint "
"tutorialspoint" : String

filter

此函式從輸入字串中過濾一組字元。僅保留透過測試的字元。

語法

String.filter test_function string_value

要在 elm REPL 中檢查函式的簽名,請鍵入以下內容:

> String.filter
<function> : (Char -> Bool) -> String -> String

簽名顯示 filter 接受兩個輸入引數並返回一個字串。第一個引數是一個函式,它以 Char 作為輸入並返回 Bool。

圖示

在示例中,我們將 Char.isUpper 作為引數傳遞給 filter 方法;它返回所有大寫字元,如下所示。

> import Char
> String.filter Char.isUpper "abcDEF"
"DEF" : String

map

此函式獲取一個字串並轉換字串中的每個字元。

語法

String.filter mapping_function string_value

要在 elm REPL 中檢查函式的簽名,請鍵入以下內容:

> String.map
<function> : (Char -> Char) -> String -> String

圖示

以下示例將字元 o 替換為 @:

> String.map (\c -> if c == 'o' then '@' else c) "TutorialsPoint"
"Tut@rialsP@int" : String

Elm - 列表

列表、元組和記錄資料結構可用於儲存值的集合。

本章討論如何在 Elm 中使用列表。

列表是同類值的集合。列表中的值必須全部為相同的資料型別。

在使用變數儲存值時,請考慮以下限制:

  • 變數本質上是標量。換句話說,在宣告時,一個變數只能儲存一個值。這意味著要在程式中儲存 n 個值,需要 n 個變數宣告。因此,當需要儲存大量值時,使用變數不可行。

  • 程式中的變數以隨機順序分配記憶體,從而難以按其宣告順序檢索/讀取值。

語法

List_name = [value1,value2,value3.....valuen]

圖示

以下示例顯示如何在 Elm 中使用列表。在 elm REPL 中嘗試此示例:

> myList1 = [10,20,30]
[10,20,30] : List number
> myList2 = ["hello","world"]
["hello","world"] : List String

如果嘗試將不同型別的值新增到列表中,編譯器將丟擲型別不匹配錯誤。如下所示。

> myList = [1,"hello"]
-- TYPE MISMATCH 
--------------------------------------------- 
repl-temp-000.elm

The 1st and 2nd entries in this list are different types of values.

4| [1,"hello"]
^^^^^^^
The 1st entry has this type:
   number
But the 2nd is:
   String

列表操作

下表顯示了列表上的常見操作:

序號 方法 描述
1 isEmpty : List a -> Bool 檢查列表是否為空
2 reverse : List a -> Bool 反轉輸入列表
3 length : List a -> Int 返回列表的大小
4 maximum : List comparable -> Maybe.Maybe comparable 返回最大值
5 minimum : List comparable -> Maybe.Maybe comparable 返回最小值
6 sum : List number -> number 返回列表中所有元素的總和
7 product : List number -> number 檢查列表是否為空
8 sort : List comparable -> List comparable 按升序排序列表
9 concat : List (List a) -> List a 將多個列表合併成一個
10 append : List a -> List a -> List a 將兩個列表合併在一起
11 range : Int -> Int -> List Int 返回從開始到結束的數字列表
12 filter : (a -> Bool) -> List a -> List a 從輸入列表中過濾值列表
13 head : List a -> Maybe.Maybe a 返回列表中的第一個元素
14 tail : : List a -> Maybe.Maybe (List a) 返回除頭部之外的所有元素

isEmpty

如果列表為空,則此函式返回 true。

語法

List.isEmpty list_name

要在 elm REPL 中檢查函式的簽名,請鍵入以下內容:

> List.isEmpty
<function> : List a -> Bool

圖示

> List.isEmpty
<function> : List a -> Bool

> List.isEmpty [10,20,30]
False : Bool

reverse

此函式反轉列表。

語法

List.reverse list_name

要在 elm REPL 中檢查函式的簽名,請鍵入以下內容:

> List.reverse
<function> : List a -> List a

圖示

> List.reverse [10,20,30]
[30,20,10] : List number

length

此函式返回列表的長度。

語法

List.length list_name

要在 elm REPL 中檢查函式的簽名,請鍵入以下內容:

> List.length
<function> : List a -> Int

圖示

> List.length [10,20,30]
3 : Int

maximum

此函式返回非空列表中的最大元素。

語法

List.maximum list_name

要在 elm REPL 中檢查函式的簽名,請鍵入以下內容:

> List.maximum
<function> : List comparable -> Maybe.Maybe comparable

圖示

> List.maximum [10,20,30]
Just 30 : Maybe.Maybe number
> List.maximum []
Nothing : Maybe.Maybe comparable

minimum

此函式返回非空列表中的最小元素。

語法

List.minimum list_name

要在 elm REPL 中檢查函式的簽名,請鍵入以下內容:

> List.minimum
<function> : List comparable -> Maybe.Maybe comparable

圖示

> List.minimum [10,20,30]
Just 10 : Maybe.Maybe number

sum

此函式返回列表中所有元素的總和。

語法

List.sum list_name

要在 elm REPL 中檢查函式的簽名,請鍵入以下內容:

> List.sum
<function> : List number -> number

圖示

> List.sum [10,20,30]
60 : number

product

此函式返回列表中所有元素的乘積。

語法

List.product list_name

要在 elm REPL 中檢查函式的簽名,請鍵入以下內容:

<function>  : List number ->  number

圖示

List.product [10,20,30]
6000 : number

sort

此函式將列表中的值從低到高排序。

語法

List.sort list_name

要在 elm REPL 中檢查函式的簽名,請鍵入以下內容:

> List.sort
<function> : List comparable -> List comparable

圖示

> List.sort [10,20,30]
[10,20,30] : List number

concat

此函式將多個列表連線成一個列表。

語法

List.concat [ [list_name1],[list_name2],[list_name3],.....[list_nameN] ]

要在 elm REPL 中檢查函式的簽名,請鍵入以下內容:

> List.concat
<function> : List (List a) -> List a

圖示

> List.concat [[10,20], [30,40],[50,60]]
[10,20,30,40,50,60] : List number

append

此函式將兩個列表放在一起。

語法

List.append [list_name1] [list_name2]

要在 elm REPL 中檢查函式的簽名,請鍵入以下內容:

> List.append
<function> : List a -> List a -> List a

圖示

> List.append [10,20] [30,40]
[10,20,30,40] : List number

++ 運算子也可用於將一個列表追加到另一個列表。如下面的示例所示:

> [10.1,20.2] ++ [30.3,40.4]
[10.1,20.2,30.3,40.4] : List Float

range

此函式建立一個數字列表,每個元素增加 1。應在列表中包含的最小和最大數字傳遞給函式。

語法

List.range start_range end_range

要在 elm REPL 中檢查函式的簽名,請鍵入以下內容:

> List.range
<function> : Int -> Int -> List Int

圖示

> List.range 1 10
[1,2,3,4,5,6,7,8,9,10] : List Int

filter

此函式從輸入列表中過濾一組值。僅保留透過測試的值。

語法

List.filter test_function input_list

要在 elm REPL 中檢查函式的簽名,請鍵入以下內容:

> List.filter
<function> : (a -> Bool) -> List a -> List a

圖示

以下示例從輸入列表中過濾所有偶數

> List.filter (\n -> n%2==0) [10,20,30,55]
[10,20,30] : List Int

head

此函式返回輸入列表中的第一個元素。

語法

List.head input_list

要在 elm REPL 中檢查函式的簽名,請鍵入以下內容:

> List.head
<function> : List a -> Maybe.Maybe a

圖示

> List.head [10,20,30,40]
Just 10 : Maybe.Maybe number
> List.head []
Nothing : Maybe.Maybe a

tail

此函式返回列表中第一個元素之後的所有元素。

語法

List.tail input_list

要在 elm REPL 中檢查函式的簽名,請鍵入以下內容:

> List.tail
<function> : List a -> Maybe.Maybe (List a)

圖示

> List.tail [10,20,30,40,50]
Just [20,30,40,50] : Maybe.Maybe (List number)
> List.tail [10]
Just [] : Maybe.Maybe (List number)
> List.tail []
Nothing : Maybe.Maybe (List a)

使用 Cons 運算子

cons 運算子 ( :: ) 將元素新增到列表的前面。

圖示

> 10::[20,30,40,50]
[10,20,30,40,50] : List number

要新增的新元素和列表中值的​​資料型別必須匹配。如果資料型別不匹配,編譯器將丟擲錯誤。

> [1,2,3,4]::[5,6,7,8]
-- TYPE MISMATCH ---------------------------------
------------ repl-temp-000.elm

The right side of (::) is causing a type mismatch.

3| [1,2,3,4]::[5,6,7,8]
			  ^^^^^^^^^
(::) is expecting the right side to be a:

   List (List number)

But the right side is:

   List number
Hint: With operators like (::) I always check the left side first. If it seems fine, 
I assume it is correct and check the right side. So the 
problem may be in how the left and right arguments interact.

列表是不可變的

讓我們檢查 Elm 中的列表是否不可變。當第一個列表 myList 與值 1 連線時,會建立一個新列表並將其返回到 myListCopy。因此,如果我們顯示初始列表,則其值將不會更改。

> myList = [10,20,30]
[10,20,30] : List number
> myListCopy = 1::myList
[1,10,20,30] : List number
> myList
[10,20,30] : List number
>myList == myListCopy
False : Bool

Elm - 元組

有時,可能需要儲存各種型別的值的集合。Elm 為我們提供了一種名為元組的資料結構來實現此目的。

元組表示異類值的集合。換句話說,元組能夠儲存不同型別的多個欄位。元組儲存固定數量的值。當您希望從函式返回不同型別的多個值時,元組很有用。這些資料結構與 elm 中的其他型別一樣是不可變的。

語法

(data1,data2)

一個簡單的示例如下所示:

> ("TuotrialsPoint",5,True,"Hyderabad")
("TuotrialsPoint",5,True,"Hyderabad") : ( String, number, Bool, String )

在我們接下來的章節中,我們將學習不同的元組操作。

first

此操作從元組中提取第一個值。

語法

Tuple.first tuple_name
> Tuple.first
<function> : ( a1, a2 ) -> a1

圖示

> Tuple.first (10,"hello")
10 : number

second

second 元組操作從元組中提取第二個值。

語法

Tuple.second tuple_name
> Tuple.second
<function> : ( a1, a2 ) -> a2

圖示

> Tuple.second (10,"hello")
"hello" : String

元組列表

列表可以儲存元組。如果在列表中使用元組,請確保它們都具有相同的資料型別並具有相同數量的引數。

圖示

> [("hello",20),("world",30)]
[("hello",20),("world",30)] : List ( String, number )

帶有函式的元組

函式可以返回元組。此外,元組可以作為引數傳遞給函式。

插圖 1

以下示例定義了一個函式 fn_checkEven。此函式接受一個整數作為引數並返回一個元組。

> fn_checkEven no = \
   if no%2 == 0 then \
      (True,"The no is Even")\
   else \
      (False,"No is not even")
<function> : Int -> ( Bool, String )
> fn_checkEven 10
(True,"The no is Even") : ( Bool, String )
> fn_checkEven 11
(False,"No is not even") : ( Bool, String )
>

插圖 2

以下將元組作為引數傳遞給函式。

> fn_add (a,b) = \
| a+b
<function> : ( number, number ) -> number
> fn_add (10,20)
30 : number

函式 fn_add 獲取一個包含 2 個數值的元組並返回它們的總和。

解構

解構涉及將元組分解成單個值。要訪問具有三個或更多元素的元組中的單個值,我們使用解構。在這裡,我們將元組中的每個值分配給不同的變數。使用 _ 可以為將被忽略或跳過的值定義佔位符。

圖示

> (first,_,_) = (10,20,30)
10 : number
> first
10 : number

圖示

在此示例中,我們將使用 let..in 塊語法進行解構。let 塊包含變數,in 塊包含應計算的表示式和應返回的值。

> t1 = (10,20,30)
(10,20,30) : ( number, number1, number2 )
> let \
(a,b,c) = t1 \
in\
a + b +c
60 : number

我們在 let 子句中宣告變數 a b c,並在 in 子句中使用它們。

Elm - 記錄

Elm 中的記錄資料結構可用於表示資料作為鍵值對。記錄可用於組織相關資料,以方便訪問和更新資料。Elm 記錄類似於 JavaScript 中的物件。記錄中的資料元素稱為欄位。

定義記錄

使用以下語法定義記錄:

語法

record_name = {fieldname1 = value1, fieldname2 = value2....fieldnameN = valueN}

記錄可以儲存多種型別的資料。記錄中的欄位名稱必須符合 Elm 識別符號命名的一般規則。

訪問記錄值

使用以下語法訪問記錄中的各個欄位。

語法

record_name.fieldname

.fieldname record_name

圖示

在 Elm REPL 中嘗試以下操作:

> company = {name="TutorialsPoint",rating=4.5}
{ name = "TutorialsPoint", rating = 4.5 } : { name : String, rating : Float }
> company.name
"TutorialsPoint" : String
> .rating company
4.5 : Float

將記錄與列表一起使用

記錄可以儲存在列表中。記錄的所有欄位值都應為相同型別。

語法

list_name = [ {field_name1 = value1},{field_name1 = value2}]

list_name = [record_name1, record_name2, record_name3....record_nameN]

圖示

在 Elm REPL 中嘗試以下操作:

> [{name = "Mohtashim"},{name = "kannan"}]
[{ name = "Mohtashim" },{ name = "kannan" }] : List { name : String }
> record1 = {name = "FirstRecord"}
{ name = "FirstRecord" } : { name : String }
> record2 = {name = "SecondRecord"}
{ name = "SecondRecord" } : { name : String }
> recordList = [record1,record2]
[{ name = "FirstRecord" },{ name = "SecondRecord" }] : List { name : String }

更新記錄

記錄在 Elm 中是不可變的。當記錄被更新時,會返回一個具有更新值的新記錄。在更新記錄時,欄位可以儲存不同型別的值。

語法

{record_name | field_name1 = new_value1, field_name2 = new_value2,field_name3 = new_value3....field_nameN = new_valueN}

圖示

在 Elm REPL 中嘗試以下操作:

> record1 = {name="FirstRecord"}
{ name = "FirstRecord" } : { name : String }
> record1_updated = {record1 | name = "FirstRecordUpdate"}
{ name = "FirstRecordUpdate" } : { name : String }
> record1
{ name = "FirstRecord" } : { name : String }
> record1 == record1_updated
False : Bool

圖示

以下示例更新記錄的多個欄位。在 Elm REPL 中嘗試以下操作:

> record3 = {a = 1,b = 2,c = 3,d = 4,e = 5}
{ a = 1, b = 2, c = 3, d = 4, e = 5 }
: { a : number, b : number1, c : number2, d : number3, e : number4 }
> record4 = {record3 | d=400 ,e=500}
{ a = 1, b = 2, c = 3, d = 400, e = 500 }
: { a : number2, b : number3, c : number4, d : number, e : number1 }
>

類型別名

類型別名定義記錄的模式。換句話說,類型別名定義了記錄可以儲存哪些欄位以及這些欄位可以儲存哪種型別的值。因此,程式設計師在賦值時不會犯遺漏任何特定屬性的錯誤。

語法

type alias alias_name = {field_name1:data_type,field_name2:data_type,....field_nameN:data_type}

圖示

在 Elm REPL 中執行以下操作:

> type alias Developer = { name:String,location:String,age:Int}
> dev1 = Developer "kannan" "Mumbai" 20
{ name = "kannan", location = "Mumbai", age = 20 } : Repl.Developer
> dev2 = Developer "mohtashim" "hyderabad" 20
{ name = "mohtashim", location = "hyderabad", age = 20 } : Repl.Developer
>

現在,如果您忘記鍵入 location 和 age,該語句將返回一個函式,該函式具有 location 和 age 欄位的輸入引數。

> dev3 = Developer "Bhagavati"
<function> : String -> Int -> Repl.Developer
We can invoke the function as shown below and pass to it the values for location and age fields.
> dev3 "Pune" 25
{ name = "Bhagavati", location = "Pune", age = 25 } : Repl.Developer

Elm - 錯誤處理

錯誤是在程式中出現的任何意外情況。錯誤可能發生在編譯時或執行時。編譯時錯誤發生在程式編譯期間(例如,程式語法錯誤),而執行時錯誤發生在程式執行期間。與其他程式語言不同,Elm 不會丟擲執行時錯誤。

考慮一個接受使用者年齡的應用程式。如果年齡為零或負數,則應用程式應丟擲錯誤。在這種情況下,Elm 應用程式可以使用錯誤處理的概念在執行時顯式地引發錯誤,如果使用者輸入零或負值作為年齡。錯誤處理指定了如果在程式執行期間發生任何意外情況時要採取的行動。

Elm 程式語言以以下方式處理錯誤:

  • MayBe
  • Result

MayBe

考慮應用程式中的搜尋功能。如果找到搜尋關鍵字,則搜尋函式返回相關資料,否則不返回任何內容。此用例可以使用 MayBe 型別在 Elm 中實現。

語法

variable_name:MayBe data_type

MayBe 型別的變數可以包含以下值之一:

  • Just some_Value - 如果有有效資料,則使用此值。

  • Nothing - 如果值不存在或未知,則使用此值。Nothing 等價於其他程式語言中的 null。

圖示

以下示例顯示瞭如何在變數和函式中使用 MayBe 型別。

步驟 1 - 建立一個 MayBeDemo.elm 檔案並向其中新增以下程式碼

-- MayBeDemo.elm
module MayBeDemo exposing(..)
import Maybe

--declaring a MayBe variable and assigning value to it
userName : Maybe String
userName = Just "Mohtashim"

--declaring a MayBe variable and assigning value to it
userAge :Maybe Int
userAge = Just 20

--declaring a MayBe variable and assigning value to it
userSalary:Maybe Float
userSalary = Nothing

--declaring a custom type
type Country = India | China | SriLanka

--defining a function that takes a String parameter as input and returns a value of type MayBe

getCountryFromString : String -> Maybe Country
getCountryFromString p =
case p of
   "India"
      -> Just India
   "China"
      -> Just China
   "SriLanka"
      -> Just SriLanka
   _
      -> Nothing

步驟 2 - 在 elm repl 中匯入模組並按如下所示執行

E:\ElmWorks\ErroApp> elm repl
---- elm-repl 0.18.0 -----------------------------------------------------------
:help for help, :exit to exit, more at 
--------------------------------------------------------------------------------
> import MayBeDemo exposing(..)
> userName
Just "Mohtashim" : Maybe.Maybe String
> userAge
Just 20 : Maybe.Maybe Int
> userSalary
Nothing : Maybe.Maybe Float
> getCountryFromString "India"
Just India : Maybe.Maybe MayBeDemo.Country
> getCountryFromString "india"
Nothing : Maybe.Maybe MayBeDemo.Country

該函式檢查傳遞給函式的值是否為印度、中國或斯里蘭卡。如果引數的值與這些值都不匹配,則返回 nothing。

Result

考慮一個示例,其中應用程式需要驗證某些條件,如果不滿足條件則引發錯誤。可以使用 Result 型別來實現此目的。如果應用程式想要顯式地引發錯誤並返回有關錯誤原因的詳細資訊,則應使用 Result 型別。

語法

Result 型別宣告接受兩個引數 - 錯誤的資料型別(通常為 String)以及如果一切順利則要返回的結果的資料型別。

type Result error_type data_value_type
= Ok data_value
| Err error_message

Result 型別返回以下值之一:

  • Ok some_value - 表示要返回的結果

  • Err - 表示如果未滿足預期條件則要返回的錯誤訊息。

插圖 1

在 Elm REPL 中嘗試以下示例 -

> String.toInt
<function> : String -> Result.Result String Int
-- successful result
> String.toInt "10"
Ok 10 : Result.Result String Int
-- unsuccessful result , Error
> String.toInt "a"
Err "could not convert string 'a' to an Int" : Result.Result String Int

String.toInt 函式如果傳遞的引數有效則返回 Integer 值。如果引數不是數字,則函式返回錯誤。

插圖 2

以下示例接受年齡作為引數。如果年齡在 0 到 135 之間,則該函式返回年齡,否則返回相應的錯誤訊息。

步驟 1 - 建立一個 ResultDemo.elm 檔案並向其中新增以下程式碼。

--ResultDemo.elm
module ResultDemo exposing(..)

userId : Result String Int
userId = Ok 10

emailId : Result String Int
emailId = Err "Not valid emailId"

isReasonableAge : String -> Result String Int
isReasonableAge input =
   case String.toInt input of
      Err r ->
         Err "That is not a age!"

   Ok age ->
      if age < 0 then
         Err "Please try again ,age can't be negative"
      else if age > 135 then
         Err "Please try agian,age can't be this big.."

   else
      Ok age

步驟 2 - 在 elm 包中匯入模組並按如下所示執行

E:\ElmWorks\ElmRepo\15_ErrorHandling\15_Code> elm repl
---- elm-repl 0.18.0 -----------------------------------------------------------
:help for help, :exit to exit, more at <https://github.com/elm-lang/elm-repl>
--------------------------------------------------------------------------------
> import ResultDemo exposing (..)
> userId
Ok 10 : Result.Result String Int
> emailId
Err "Not valid emailId" : Result.Result String Int
> isReasonableAge "10"
Ok 10 : Result.Result String Int
> isReasonableAge "abc"
Err "That is not a age!" : Result.Result String Int

Elm - 架構

在本章中,我們將討論在 Elm 平臺上建立應用程式的標準方法。Elm 使用類似於 Model-View-Controller 模式的架構模式。

以下是 Elm 架構的四個主要部分。

  • 模型 (Model)
  • 檢視 (View)
  • 訊息 (Message)
  • 更新 (Update)
Architecture

Elm 架構如何工作

模型包含應用程式狀態。例如,如果應用程式顯示客戶列表,則狀態將包含每個客戶資料。為了以可呈現的方式顯示狀態,必須生成一個檢視/html。一旦使用者透過按下按鈕或在表單中鍵入資料與檢視互動,檢視就會生成稱為訊息的訊號。訊息傳遞給更新方法,該方法評估訊息並採取適當的措施。因此,更新方法將生成一個新的模型。

新模型生成一個新的檢視。檢視將導致使用者發出新的互動以發出訊息,這些訊息將傳遞到更新函式。此外,該函式會建立一個新模型。因此,迴圈重複,如上圖所示。

模型 (Model)

模型處理應用程式的狀態。定義模型的語法如下所示:

-- Model syntax

type alias Model = {
   property1:datatype,
   proptery2:datatype
...
}

要建立模型,我們需要首先建立一個包含所有所需屬性的模板。每個屬性都指定應用程式的狀態。

檢視 (View)

檢視是應用程式狀態的視覺表示。檢視知道如何獲取資料並從中生成網頁。當用戶與檢視互動時,使用者可以透過生成訊息來操作狀態。定義檢視的語法如下所示:

--View Syntax
view model =some_implementation

訊息 (Message)

訊息是使用者更改應用程式狀態的請求。訊息作為引數傳遞給更新函式。

--Message Syntax
type Message = Message1 |Message2 ...

語法顯示了一個 Message 型別。elm 應用程式將根據傳遞給它的訊息來編輯狀態。這些決策是在更新方法中做出的。

更新 (Update)

更新函式解釋作為引數傳遞給它的訊息,並更新模型。

--Update Syntax
update Message_type model =
   some_implementation

更新函式將訊息和模型作為引數。

Elm - 包管理器

包管理器是一個命令列工具,它自動化了在應用程式中安裝、升級、配置和刪除包的過程。

就像 JavaScript 有一個名為 npm 的包管理器一樣,elm 有一個名為elm-package的包管理器。

包管理器執行以下三個任務:

  • 安裝 elm 應用程式所需的所有依賴項
  • 釋出自定義包
  • 在您準備好釋出和更新時確定包的版本。

Elm 包管理器命令

下表列出了各種 Elm 包管理器命令:

序號 命令 語法 描述
1 安裝 (install) elm-package install 安裝要本地使用的包
2 釋出 (publish) elm-package publish 將您的包釋出到中央目錄
3 更新版本 (bump) elm-package bump 根據 API 更改更新版本號
4 差異 (diff) elm-package diff 獲取兩個 API 之間的差異

為了釋出您的包,您需要在 GitHub 上託管原始碼,並使用 git 標籤正確標記版本。下圖顯示瞭如何使用 elm-package 管理器拉取外部依賴項。

圖示 - 安裝 svg 包

在此示例中,我們將瞭解如何將可縮放向量圖形 (SVG) 整合到 elm 應用程式中。

步驟 1 - 建立一個資料夾 elmSvgApp

步驟 2 - 使用以下命令安裝 svg 包:

elm-package install elm-lang/svg

步驟 3 - 安裝 建立一個 SvgDemo.elm 檔案並鍵入以下內容。我們匯入 Svg 模組以繪製一個100x100尺寸的矩形並填充紅色。

import Svg exposing (..)
import Svg.Attributes exposing (..)

main =
   svg
   [ width "120"
   , height "120"
   , viewBox "0 0 120 120"
   ]
   [ rect
      [ x "10"
      , y "10"
      , width "100"
      , height "100"
      , rx "15"
      , ry "15"
      ,fill "red"
      ]
      []
   ]

步驟 4 - 現在使用 elm make .\SvgDemo.elm 構建專案。這將生成一個 index.html,如下所示:

build project

Elm - 訊息

訊息是 Elm 架構中的一個元件。這些元件由檢視響應使用者與應用程式介面的互動而生成。訊息表示使用者更改應用程式狀態的請求。

語法

--Message Syntax
type Message = some_message1 |some_message2 ...|some_messageN

圖示

以下示例是一個簡單的計數器應用程式。當用戶分別點選“新增”和“減去”按鈕時,該應用程式會將變數的值增加或減少 1。

該應用程式將有 4 個元件。元件如下所述:

訊息 (Message)

此示例的訊息將為:

type Message = Add | Subtract

模型 (Model)

模型表示應用程式的狀態。在計數器應用程式中,模型定義如下;計數器的初始狀態將為零。

model = 0

檢視 (View)

視圖表示應用程式的視覺元素。檢視包含兩個按鈕(+)和(-)。當用戶分別點選 + 和 - 按鈕時,檢視會生成 Add 和 Subtract 訊息。然後,檢視顯示模型的修改值。

view model =
-- invoke text function
h1[]
[   div[] [text "CounterApp from TutorialsPoint" ]
   ,button[onClick Subtract] [text "-"]
   ,div[][text (toString model)]
   ,button[onClick Add] [text "+"]
]

更新 (Update)

此元件包含應為檢視生成的每個訊息執行的程式碼。這在下面的示例中顯示:

update msg model =
case msg of
Add -> model+1
Subtract -> model-1

將所有內容放在一起

步驟 1 - 建立一個資料夾MessagesApp 和檔案 MessagesDemo.elm

步驟 2 - 在 elm 檔案中新增以下程式碼:

import Html exposing (..)
import Html.Events exposing(onClick)

model = 0 -- Defining the Model

--Defining the View

view model =
   h1[]
   [  div[] [text "CounterApp from TutorialsPoint" ]
      ,button[onClick Subtract] [text "-"]
      ,div[][text (toString model)]
      ,button[onClick Add] [text "+"]
   ]

--Defining the Messages

type Message = Add | Subtract

--Defining Update

update msg model =
case msg of
   Add -> model+1
   Subtract -> model-1

-- Define the main method
main =
   beginnerProgram
   {
      model=model
      ,view=view
      ,update=update
   }

步驟 3 - 在終端中執行elm make 命令elm make 命令編譯程式碼並從上面建立的 .elm 檔案生成 HTML 檔案。

C:\Users\dell\elm\MessagesApp> elm make .\MessageDemo.elm
Some new packages are needed. Here is the upgrade plan.

   Install:
      elm-lang/core 5.1.1
      elm-lang/html 2.0.0
      elm-lang/virtual-dom 2.0.4

Do you approve of this plan? [Y/n] y
Starting downloads...

   ΓùÅ elm-lang/html 2.0.0
   ΓùÅ elm-lang/virtual-dom 2.0.4

ΓùÅ elm-lang/core 5.1.1
Packages configured successfully!
Success! Compiled 38 modules.
Successfully generated index.html

步驟 4 - 開啟index.html並驗證工作情況,如下所示:

elm make command

Elm - 命令

在前面的章節中,我們討論了 Elm 架構的各個元件及其功能。使用者和應用程式使用訊息相互通訊。

考慮一個示例,其中應用程式需要與其他元件(如外部伺服器、API、微服務等)通訊以服務使用者請求。這可以透過在 Elm 中使用命令來實現。訊息和命令不是同義詞。訊息表示終端使用者與應用程式之間的通訊,而命令表示 Elm 應用程式如何與其他實體通訊。命令是響應訊息觸發的。

下圖顯示了複雜 Elm 應用程式的工作流程:

Workflow

使用者與檢視互動。檢視根據使用者的操作生成相應的訊息。更新元件接收此訊息並觸發命令。

語法

定義命令的語法如下所示:

type Cmd msg

檢視生成的訊息傳遞給命令。

圖示

以下示例向 API 發出請求並顯示 API 返回的結果。

該應用程式從使用者處接受一個數字,將其傳遞給 Numbers API。此 API 返回與數字相關的 facts。

應用程式的各個元件如下:

Http 模組

Elm 的 Http 模組用於建立和傳送 HTTP 請求。此模組不是核心模組的一部分。我們將使用 elm 包管理器來安裝此包。

API

在此示例中,應用程式將與 Numbers API 通訊 - "http://numbersapi.com/#42"。

檢視 (View)

應用程式的檢視包含一個文字框和一個按鈕。

view : Model -> Html Msg
view model =
   div []
      [ h2 [] [text model.heading]
      ,input [onInput Input, value model.input] []
      , button [ onClick ShowFacts ] [ text "show facts" ]
      , br [] []
      , h3 [][text model.factText]
      ]

模型 (Model)

模型表示使用者輸入的值以及 API 將返回的結果。

type alias Model =
   { heading : String
   , factText : String
   , input :String
   }

訊息 (Message)

該應用程式有以下三個訊息:

  • ShowFacts
  • Input
  • NewFactArrived

單擊Show Facts按鈕時,ShowFacts訊息將傳遞到更新方法。當用戶在文字框中鍵入某些值時,Input訊息將傳遞到更新方法。最後,當收到 Http 伺服器響應時,NewFactArrived訊息將傳遞到更新。

type Msg
   = ShowFacts
   |Input String
   | NewFactArrived (Result Http.Error String)

更新 (Update)

更新方法返回一個元組,其中包含模型和命令物件。當用戶單擊 Show Facts 按鈕時,訊息將傳遞到更新,然後更新呼叫 NumbersAPI。

update : Msg -> Model -> (Model, Cmd Msg)
update msg model =
   case msg of
      Input newInput ->
      (Model "NumbersApi typing.." "" newInput ,Cmd.none)
      ShowFacts ->
         (model, getRadmonNumberFromAPI model.input)

      NewFactArrived (Ok newFact) ->
         (Model "DataArrived" newFact "", Cmd.none)

      NewFactArrived (Err _) ->
      (model, Cmd.none)

輔助函式

輔助函式getRandomNumberFromAPI呼叫 NumbersAPI 並將使用者輸入的數字傳遞給它。API 返回的結果用於更新模型。

getRadmonNumberFromAPI : String->Cmd Msg
getRadmonNumberFromAPI newNo =
   let
      url =
         "http://numbersapi.com/"++newNo
   in
      Http.send NewFactArrived (Http.getString url)
序號 方法 簽名 描述
1 Http.getString getString : String -> Request String 建立一個 GET 請求並將響應正文解釋為字串。
2 Http.send

傳送:(Result Error a -> msg) -> Request a -> Cmd msg 傳送一個 HTTP 請求。

主函式

這是 Elm 專案的入口點。

main =
   Html.program
      { init = init
      , view = view
      , update = update
      , subscriptions = subscriptions
      }

將所有內容放在一起

步驟 1 − 建立資料夾 CommandApp 和檔案 CommandDemo.elm。

步驟 2 − 使用命令 elm package install elm-lang/http 安裝 http 模組。

步驟 2 − 輸入 CommandDemo.elm 的內容,如下所示:

import Html exposing (..)
import Html.Attributes exposing (..)
import Html.Events exposing (..)
import Http

main =
   Html.program
      { init = init
      , view = view
      , update = update
      , subscriptions = subscriptions
      }

-- MODEL
type alias Model =
   { heading : String
   , factText : String
   , input :String
   }

init : (Model, Cmd Msg)
init =
   ( Model "NumbersAPI" "NoFacts" "42"-- set model two fields
   , Cmd.none -- not to invoke api initially
   )

-- UPDATE

type Msg
   = ShowFacts
   |Input String
   | NewFactArrived (Result Http.Error String)

update : Msg -> Model -> (Model, Cmd Msg)
update msg model =
   case msg of
      Input newInput ->
      (Model "NumbersApi typing.." "" newInput ,Cmd.none)
      ShowFacts ->
         (model, getRadmonNumberFromAPI model.input)

      NewFactArrived (Ok newFact) ->
         (Model "DataArrived" newFact "", Cmd.none)

      NewFactArrived (Err _) ->
         (model, Cmd.none)

- VIEW

view : Model -> Html Msg
view model =
   div []
      [ h2 [] [text model.heading]
      ,input [onInput Input, value model.input] []
      , button [ onClick ShowFacts ] [ text "show facts" ]
      , br [] []
      , h3 [][text model.factText]
      ]

-- SUBSCRIPTIONS

subscriptions : Model -> Sub Msg
subscriptions model =
   Sub.none

-- HTTP

getRadmonNumberFromAPI : String->Cmd Msg
getRadmonNumberFromAPI newNo =
   let
      url =
      "http://numbersapi.com/"++newNo
   in
      Http.send NewFactArrived (Http.getString url)

步驟 4 − 執行命令。

C:\Users\dell\elm\CommandApp> elm make .\CommandDemo.elm

這將生成如下所示的 html 檔案。

Generate html

Elm - 訂閱

在上一章中,我們討論了 View 如何使用命令與其他元件互動。類似地,元件(例如 WebSocket)可以透過訂閱與 View 互動。訂閱是 Elm 應用程式接收外部輸入(如鍵盤事件、計時器事件和 WebSocket 事件)的一種方式。

下圖說明了訂閱在 Elm 應用程式中的作用。使用者透過訊息與 Elm 應用程式互動。給定的應用程式使用 WebSocket,並且有兩種操作模式:

  • 透過命令將客戶端資料傳送到套接字伺服器
  • 透過訂閱隨時接收來自套接字伺服器的資料
socket server

語法

定義訂閱的語法如下所示:

type Sub msg

圖示

讓我們透過一個簡單的例子來了解訂閱。

在下面的示例中,應用程式向伺服器傳送訊息。伺服器是一個回顯伺服器,它使用相同的訊息回覆客戶端。所有傳入的訊息隨後都會顯示在一個列表中。我們將使用 WebSocket(wss 協議)來持續監聽來自伺服器的訊息。WebSocket 將使用命令將使用者輸入傳送到伺服器,同時將使用訂閱接收來自伺服器的訊息。

應用程式的各個元件如下所示:

回顯伺服器

可以使用 wss 協議訪問回顯伺服器。回顯伺服器將使用者輸入傳送回應用程式。定義回顯伺服器的程式碼如下所示:

echoServer : String
echoServer =
"wss://echo.websocket.org"

模型 (Model)

模型表示使用者輸入和來自套接字伺服器的傳入訊息列表。定義模型的程式碼如下所示:

type alias Model =
   { input : String
   , messages : List String
   }

訊息

訊息型別將包含 Input 用於獲取使用者的文字輸入。當用戶點選按鈕將訊息傳送到 WebSocket 伺服器時,將生成 Send 訊息。當從回顯伺服器收到訊息時,將使用 NewMessage。

type Msg
   = Input String
   | Send
   | NewMessage String

檢視 (View)

應用程式的檢視包含一個文字框和一個提交按鈕,用於將使用者輸入傳送到伺服器。伺服器的響應使用 div 標籤在檢視中顯示。

view : Model -> Html Msg
view model =
   div []
      [ input [onInput Input, value model.input] []
      , button [onClick Send] [text "Send"]
      , div [] (List.map viewMessage (List.reverse model.messages))
      ]

viewMessage : String -> Html msg
viewMessage msg =
   div [] [ text msg ]

更新 (Update)

更新函式接收訊息和模型元件。它根據訊息型別更新模型。

update : Msg -> Model -> (Model, Cmd Msg)
update msg {input, messages} =
   case msg of
      Input newInput ->
         (Model newInput messages, Cmd.none)

   Send ->
      (Model "" messages, WebSocket.send echoServer input)

   NewMessage str ->
      (Model input (str :: messages), Cmd.none)
序號 方法 簽名 描述
1 WebSocket.listen listen : String -> (String -> msg) -> Sub msg 訂閱 WebSocket 上的任何傳入訊息。
2 WebSocket.send send : String -> String -> Cmd msg 向伺服器地址傳送 wss 請求。重要的是,您也已使用 listen 訂閱了此地址。如果沒有,將建立 WebSocket 以傳送一條訊息然後關閉。

訂閱

訂閱函式接收模型物件。為了接收來自 WebSocket 伺服器的訊息,我們呼叫 WebSocket.listen 並將訊息作為 NewMessage 傳遞。當從伺服器收到新訊息時,將呼叫更新方法。

subscriptions : Model -> Sub Msg
subscriptions model =
WebSocket.listen echoServer NewMessage

主函式

主函式是 Elm 應用程式的入口點,如下所示。

main =
   Html.program
      { init = init
      , view = view
      , update = update
      , subscriptions = subscriptions
      }

將所有內容放在一起

步驟 1 − 建立一個目錄 SubscriptionApp 並向其中新增一個檔案 SubscriptionDemo.elm。

步驟 2 − 將以下內容新增到 SubscriptionDemo.elm 檔案中:

import Html exposing (..)
import Html.Attributes exposing (..)
import Html.Events exposing (..)
import WebSocket

main =
   Html.program
      { init = init
      , view = view
      , update = update
      , subscriptions = subscriptions
      }

echoServer : String
echoServer =
   "wss://echo.websocket.org"

-- MODEL

type alias Model =
   { input : String
   , messages : List String
   }

init : (Model, Cmd Msg)
init =
   (Model "" [], Cmd.none)

-- UPDATE
type Msg
   = Input String
   | Send
   | NewMessage String

update : Msg -> Model -> (Model, Cmd Msg)
update msg {input, messages} =
   case msg of
      Input newInput ->
      (Model newInput messages, Cmd.none)

   Send ->
      (Model "" messages, WebSocket.send echoServer input)

   NewMessage str ->
      (Model input (str :: messages), Cmd.none)

-- SUBSCRIPTIONS
subscriptions : Model -> Sub Msg
subscriptions model =
   WebSocket.listen echoServer NewMessage

-- VIEW
view : Model -> Html Msg
view model =
   div []
      [ input [onInput Input, value model.input] []
      , button [onClick Send] [text "Send"]
      , div [] (List.map viewMessage (List.reverse model.messages))
      ]

viewMessage : String -> Html msg
viewMessage msg =
div [] [ text msg ]

步驟 3 − 使用 elm 包管理器安裝 websockets 包。

C:\Users\dell\elm\SubscriptionApp> elm-package install elm-lang/websocket

步驟 4 − 構建並生成 index.html 檔案,如下所示。

C:\Users\dell\elm\SubscriptionApp> elm make .\SubscriptionDemo.elm

步驟 5 − 執行後,將生成以下輸出:

SubscriptionApp
廣告

© . All rights reserved.