Elm-クイックガイド

Elmは関数型プログラミング言語です。2012年にEvanCzaplickiによって設計されました。

Elmは、特にWebアプリケーションのフロントエンドの設計に使用されます。

ElmはJavaScriptにコンパイルされ、ブラウザで実行されます。高速で、テスト可能で、保守可能であり、ランタイム例外はありません。

Elmプログラミングプラットフォームのいくつかの実用的なアプリケーションは次のとおりです。

  • Games
  • Graphics
  • シングルページアプリケーション

なぜエルム

Elmは、フロントエンド開発者が直面する一般的な問題のほとんどを排除します。これには以下が含まれます-

ランタイム例外なし

Elmは静的に型付けされた言語です。考えられるすべてのエラーは、コンパイル時に検証および修正されます。これにより、実行時の例外が発生しなくなります。

開発者向けのエラーメッセージ

他のプログラミング言語とは異なり、Elmのコンパイラは、コンパイル時に非常に具体的で開発者にわかりやすいエラーメッセージを提供するように設計されています。エラーメッセージには、推奨される設計ドキュメントへのリンクなどのヒントも含まれています。

テストが簡単

Elmの各関数は、他のすべての関数とは別にテストできます。これにより、Elmで記述されたプログラムを簡単にテストできます。

自動セマンティックバージョニング

Elmは、パッケージの自動セマンティックバージョニングを実施します。これにより、パッチを変更しても、すでに実行中のアプリケーションがクラッシュすることはありません。

再利用可能なコード

Elm関数は、JavaScript、Python、またはTypeScriptの関数と比較して、本質的に再利用が容易です。

この章では、Windows、Mac、およびLinuxプラットフォームにElmをインストールする手順について説明します。

ローカル環境のセットアップ

Elmをローカル環境にインストールするには、以下に示す手順を検討してください。

Step 1 − Install node

elmはJavaScriptにコンパイルされているため、ターゲットマシンには nodeインストールされています。セットアップの手順については、TutorialsPointNodeJSコースを参照してくださいnode そして npm

ノードのセットアップ。

Step 2 − Install elm

ターミナルで次のコマンドを実行して、elmをインストールします。このコースの執筆時点では、elmの安定バージョンは0.18であったことに注意してください。

npm install -g [email protected]

インストール後、次のコマンドを実行してElmのバージョンを確認します。

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

Step 2 − Install the Editor

ここで使用する開発環境は、Visual Studio Code(Windowsプラットフォーム)です。

Visual Studio Codeは、VisualStudioのオープンソースIDEです。Mac OS X、Linux、およびWindowsプラットフォームで使用できます。VSCodeはで入手できます

Windowsへのインストール

このセクションでは、WindowsにElmをインストールする手順について説明します。

ダウンロード https://code.visualstudio.com/。Windows用。

VSCodeSetup.exeをダブルクリックして、セットアッププロセスを起動します。これには1分しかかかりません。

[ファイル]→[コマンドプロンプトで開く]を右クリックすると、ファイルのパスに直接移動できます。同様に、[エクスプローラーで表示]オプションは、ファイルエクスプローラーにファイルを表示します。

Mac OSXへのインストール

Visual StudioCodeのMacOSX固有のインストールガイドは次の場所にあります。 VSCodeのインストール-MAC。

Linuxへのインストール

Visual Studio CodeのLinux固有のインストールガイドは、次の場所にあります。 VSCodeのインストール-Linux。

Step 4 − Install the elm Extension

以下に示すように、VSCodeにelm拡張機能をインストールします。

Elm REPL

REPLはReadEval PrintLoopの略です。これは、コマンドが入力され、システムが対話モードで出力を返すWindowsコンソールやUnix / Linuxシェルなどのコンピューター環境を表します。

ElmにはREPL環境がバンドルされています。次のタスクを実行します-

  • 読み取り-ユーザーの入力を読み取り、入力をelmデータ構造に解析して、メモリに格納します。

  • Eval-データ構造を取得して評価します。

  • 印刷-結果を印刷します。

  • ループ-ユーザーが終了するまで、上記のコマンドをループします。コマンド:exitを使用してREPLを終了し、ターミナルに戻ります。

REPLで2つの数値を追加する簡単な例を以下に示します-

VSCodeターミナルを開き、コマンドelmREPLを入力します。

REPL端末は、ユーザーが何らかの入力を入力するのを待ちます。次の式10+ 20を入力します。REPL環境は、以下のように入力を処理します。

  • ユーザーから番号10と20を読み取ります。

  • +演算子を使用して評価します。

  • 結果を30として出力します。

  • 次のユーザー入力のためにループします。ここでループを終了します。

この章では、elmで簡単なプログラムを作成する方法について説明します。

Step 1 − Create a directory HelloApp in VSCode

ここで、ファイルを作成します- Hello.elm このディレクトリにあります。

上の図はプロジェクトフォルダを示しています HelloApp VSCodeで端末が開かれました。

Step 2 − Install the necessary elm packages

elmのパッケージマネージャーはelm-packageです。elm-lang / htmlパッケージをインストールします。このパッケージは、ブラウザでelmコードの出力を表示するのに役立ちます。

にトラバースします HelloApp VSCodeの[ファイル]→[コマンドプロンプトで開く]を右クリックして、プロジェクトフォルダーを作成します。

ターミナルウィンドウで次のコマンドを実行します-

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

パッケージのインストール時に、次のファイル/フォルダがプロジェクトディレクトリに追加されます。

  • elm-package.json(ファイル)、プロジェクトのメタデータを保存します
  • elm-stuff(フォルダー)、外部パッケージを格納します

パッケージが正常にインストールされると、次のメッセージが表示されます。

Step 3 − Add the following code to the Hello.elm file

-- 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 ブラウザで。

このために、関数をインポートする必要があります text 以内 Htmlモジュール。text関数は、ブラウザで任意の文字列値を出力するために使用されます。主な方法は、プログラムへのエントリポイントです。主な方法は、呼び出すテキスト機能を、そこに文字列値を渡します。

Step 4 − Compile the project

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 ファイル。

Step 5 − Open the index.html in the browser

index.htmlファイルを任意のブラウザで開きます。出力は以下のようになります−

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型システムは、次の数値型をサポートします-

シニア番号 タイプ
1 数値-任意の数値を格納します 7は数値型です
2 Float-小数値を格納します 7/2はフロートとして3.5の結果を与えます
3 Int-非小数値を格納します 7 // 2はIntとして3つの結果を与えます

タイプ番号は、小数値と非小数値の両方に対応します。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
>

文字列と文字

文字列データ型は、文字のシーケンスを表すために使用されます。Charデータ型は、単一の文字を表すために使用されます。文字列値は、二重引用符内で定義されている」とシャアの値は、単一引用符」で囲まれています。

シニア番号 タイプ
1 文字列-文字のシーケンスを格納します 「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の2つの値のみをサポートします。キーワード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は、ユーザー定義型の作成をサポートしています。たとえば、支払いアプリケーションについて考えてみます。アプリケーションは、クレジットカード、デビットカード、ネットバンキングなどのさまざまな支払い方法を保存する必要があります。これは、カスタムタイプを定義し、その値を3つの受け入れ可能な支払いモードに制限することで実現できます。

次の例は、カスタム型を作成する方法を示しています。

> 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は、次の構造化データ型をサポートしています-

  • Tuple
  • List
  • Record
  • Record

これらについては、次の章で詳しく説明します。

変数は、定義上、値を格納する「メモリ内の名前付きスペース」です。つまり、プログラム内の値のコンテナとして機能します。変数は、プログラムが値を格納および操作するのに役立ちます。

Elmの変数は、特定のデータ型に関連付けられています。データ型は、変数のメモリのサイズとレイアウト、そのメモリ内に格納できる値の範囲、および変数に対して実行できる一連の操作を決定します。

可変命名規則-ルール

このセクションでは、変数の命名規則について学習します。

  • 変数名は、文字、数字、および下線文字で構成できます。
  • 変数名を数字で始めることはできません。文字またはアンダースコアで始まる必要があります。
  • Elmでは大文字と小文字が区別されるため、大文字と小文字は区別されます。

Elmでの変数宣言

Elmで変数を宣言するための型構文を以下に示します-

構文1

variable_name:data_type = value

「:」構文(型注釈と呼ばれる)は、変数をデータ型に関連付けるために使用されます。

構文2

variable_name = value-- no type specified

Elmで変数を宣言するとき、データ型はオプションです。この場合、変数のデータ型は、割り当てられた値から推測されます。

この例では、VSCodeエディターを使用してelmプログラムを作成し、elmreplを使用して実行します。

Step 1 − Create a project folder - VariablesApp. Create a Variables.elm file in the project folder.

次の内容をファイルに追加します。

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

プログラムはモジュール変数を定義します。モジュールの名前は、elmプログラムファイルの名前と同じである必要があります。(..)構文は、モジュール内のすべてのコンポーネントを公開するために使用されます。

プログラムは、String型の変数メッセージを宣言します。

Step 2 − Execute the program.

  • VSCodeターミナルで次のコマンドを入力して、elmREPLを開きます。
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は文字列変数であり、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

オペレーターは、データに対して実行される関数を定義します。演算子が作用する値は、オペランドと呼ばれます。次の式を考えてみましょう

7 + 5 = 12

ここで、値7、5、および12はオペランドであり、+および=は演算子です。

Elmの主要な演算子は次のように分類できます-

  • Arithmetic
  • Relational
  • Logical

算術演算子

変数aとbの値がそれぞれ7と2であると仮定します。

例を表示

シニア番号 オペレーター 説明
1 +(追加) オペランドの合計を返します a + bは9です
2 -(減算) 値の差を返します abは5です
3 *(乗算) 値の積を返します a * bは14です
4 /(フロート部門) 除算演算を実行し、浮動商を返します a / bは3.5です
5 //(整数除算) 除算演算を実行し、整数の商を返します a // bは3
6 % (係数) 除算演算を実行し、余りを返します a%bは1です

関係演算子

関係演算子は、2つのエンティティ間の関係の種類をテストまたは定義します。これらの演算子は、2つ以上の値を比較するために使用されます。関係演算子はブール値、つまり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)は偽です
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
>

論理演算子

論理演算子は、2つ以上の条件を組み合わせるために使用されます。論理演算子もブール値を返します。

例を表示

シニア番号 オペレーター 説明
1 && 指定されたすべての式がtrueを返す場合にのみ、演算子はtrueを返します (10> 5)&&(20> 5)はTrueを返します
2 || 指定された式の少なくとも1つがtrueを返す場合、演算子はtrueを返します (10 <5)|| (20> 5)はTrueを返します
3 ない 演算子は、式の結果の逆数を返します。例:!(> 5)はfalseを返します。 not(10 <5)はTrueを返します
4 xor 演算子は、1つの入力がtrueを返す場合にのみtrueを返します。両方の式がtrueを返す場合、演算子はfalseを返します。 xor(10> 5)(20> 5)はfalseを返します

意思決定構造では、プログラマーは、プログラムによって評価またはテストされる1つ以上の条件と、条件が真であると判断された場合に実行される1つまたは複数のステートメント、およびオプションで、条件はfalseと判断されます。

以下に示すのは、ほとんどのプログラミング言語に見られる典型的な意思決定構造の一般的な形式です。

意思決定構造は、命令が実行される前に条件を評価します。Elmの意思決定構造は次のように分類されます-

シニア番号 ステートメント 説明
1 if ... then ... elseステートメント ifステートメントは、ブール式と、それに続く式がtrueを返した場合に実行されるthenと、式がfalseを返した場合に実行されるelseで構成されます。
2 ネストされたifステートメント 1つのif ... then ... elseを別のif内で使用できます。
3 ケースステートメント 値のリストに対して変数の値をテストします。

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 boolean_expression1 then statement1_ifTrue else if boolean_expression2 then statement2_ifTrue else statement3_ifFalse

ElmREPLで次の例を試してください-

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

ケースステートメント

caseステートメントを使用して、if thenelseステートメントを簡略化できます。caseステートメントの構文は次のとおりです-

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

caseステートメントは、変数の値が事前定義された定数のセットと一致するかどうかを確認し、対応する値を返します。それぞれの場合に返される値は同じタイプでなければならないことに注意してください。変数の値が指定された定数のいずれとも一致しない場合、制御は*デフォルト*(// _で示される)に渡され、対応する値が返されます。

ElmREPLで次の例を試してください-

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

上記のコードスニペットは、nの値がゼロかどうかをチェックします。制御はデフォルトに渡され、文字列「nはゼロではありません」が返されます。

Elmは関数型プログラミング言語です。Elmは、従来のループ構造の代わりに再帰の概念を使用します。

この章では、再帰の概念について説明します。

再帰

一部のコンピュータープログラミング言語では、モジュールまたは関数がそれ自体を呼び出すことができます。この手法は再帰として知られています。

このプログラムでは、再帰を使用してhelloを5回表示する方法を説明します。

Step 1 − Create a file Loop.elm

モジュールループを作成し、関数を定義します 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を作成し、同じ関数を呼び出します。

Step 2 − Invoke sayHello from REPL

現在のプロジェクトフォルダー(Loop.elmファイルの場所)からelmREPLを開きます。

//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
>

次の例では、再帰を使用してn個の数値の合計を出力します。

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

elm REPLでは、入力番号を受け取り、0からその番号までのすべての数値を合計する関数sumOfNosを作成しました。

たとえば、入力を5として渡すと、合計は1 + 2 + 3 + 4 + 5、つまり15になります。

> ssumOfNos 5
15 : number

プログラムの出力は上に示されています。

関数は、Elmプログラムの構成要素です。関数は、特定のタスクを実行するための一連のステートメントです。

関数は、プログラムをコードの論理ブロックに編成します。定義すると、関数を呼び出してコードにアクセスできます。これにより、コードが再利用可能になります。さらに、関数を使用すると、プログラムのコードを簡単に読み取って保守できます。

関数を使用する手順

関数を使用するには3つのステップがあります-

関数宣言

関数宣言は、関数の名前、戻り値の型、およびパラメーターについてコンパイラーに通知します。関数を宣言するための構文を以下に示します-

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を定義しています。この関数は、パラメーターとして2つの数値を受け入れ、それらの合計を返します。elmREPLで次のことを試してください-

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

イラスト2

次の例では、関数sayHelloを定義しています。sayHello関数は、パラメーターとして文字列値を受け入れて返し、文字列を返します。

> 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

最初の例では、リストを結合メソッドにチェーンしています。2番目のケースでは、同じリストがパイプで逆関数になり、その後パイプで結合されます。そのため、リストは逆に表示され、結合されます。

Unicode文字のシーケンスは文字列と呼ばれます。Elmでは、文字列は ""二重引用符で囲まれています。文字列は、以下に示すようにテキストのチャンクです。

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

文字列関数

文字列値のクエリまたは操作に使用できるいくつかの一般的な関数を以下に示します。REPLを使用して、以下の例を試してください。

シニアいいえ 方法 説明
1 isEmpty:文字列->ブール 文字列が空であることを確認します
2 逆:文字列->文字列 入力文字列を反転します
3 長さ:文字列->整数 整数の長さを返します
4 追加:文字列->文字列->文字列 2つの文字列を追加し、新しい文字列を返します
5 追加:文字列-> Sconcat:リスト文字列->文字列 文字列のリストを追加し、新しい文字列を返します
6 分割:文字列->文字列->リスト文字列 指定されたセパレータを使用して入力文字列を分割し、文字列リストを返します
7 スライス:Int-> Int-> String-> String 開始、終了インデックス、および入力文字列を指定して部分文字列を返します
8 含む:文字列->文字列->ブール 2番目の文字列に最初の文字列が含まれている場合はtrueを返します
9 toInt:String-> Result.Result String Int 文字列を整数に解析します
10 toInt:String-> Result.Result String Int 文字列を整数に解析します
11 toFloat:文字列-> Result.Result String Float 文字列を解析してフロートします
12 fromChar:文字->文字列 指定された文字から文字列を作成します。
13 toList:文字列->リスト文字 文字列を文字のリストに変換します
14 fromList:リスト文字->文字列 文字のリストを文字列に変換します
15 toUpper:文字列->文字列 入力文字列を大文字に変換します
16 トリム:文字列->文字列 文字列の両側の空白を取り除きます。
17 フィルタ:(Char-> Bool)->文字列->文字列 入力文字列から文字セットをフィルタリングします
18 マップ:(文字->文字)->文字列->文字列 入力文字列のすべての文字を変換します

isEmpty

この関数を使用して、文字列が空かどうかを判別できます。指定された文字列が空の場合、この関数はTrueを返します。

構文

String.isEmpty String_value

関数のシグネチャをチェックするには、elmREPL-に次のように入力します。

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

関数のシグネチャは、戻り値の型としてBoolを示し、文字列として入力型を示します-

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

逆行する

この関数は文字列を反転します。

構文

String.reverse String_value

関数のシグネチャをチェックするには、elmREPL-に次のように入力します。

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

関数のシグネチャは、戻り値の型として文字列を示し、文字列として入力型を示します-

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

長さ

この関数は、文字列の長さを返します。

構文

String.length String_value

関数のシグネチャをチェックするには、elmREPL-に次のように入力します。

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

関数のシグネチャは、戻り値の型としてIntを示し、文字列として入力型を示します。

> String.length "Mohtashim"
9 : Int

追加

この関数は、2つの文字列を追加して、新しい文字列を返します。

構文

String.append String_value1 String_value2

関数のシグネチャをチェックするには、elmREPL-に次のように入力します。

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

の署名は、2つの文字列入力パラメータと1つの文字列出力パラメータを示しています

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

concat

この関数は、多くの文字列を1つに連結することにより、新しい文字列を返します。

構文

String.concat [String1,String2,String3]

関数のシグネチャをチェックするには、elmREPL-に次のように入力します。

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

の署名は、文字列入力パラメータと文字列戻り値の型のリストを示しています

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

スプリット

この関数は、指定された区切り文字を使用して文字列を分割します。

構文

String.split string_seperator String_value

関数のシグネチャをチェックするには、elmREPL-に次のように入力します。

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

の署名は、2つの入力文字列パラメータと文字列タイプのリストとして出力を示します。

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

スライス

この関数は、開始インデックスと終了インデックスを指定して部分文字列を返します。負のインデックスは、リストの最後から取得されます。インデックスの値はゼロから始まります。

構文

String.slice start_index end_index String_value

関数のシグネチャをチェックするには、elmREPL-に次のように入力します。

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

の署名は、3つの入力パラメーターと1つの戻り値の型を示しています。

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

含まれています

この関数は、2番目の文字列に最初の文字列が含まれている場合にTrueを返します。

構文

String.contains string1 string2

関数のシグネチャをチェックするには、elmREPL-に次のように入力します。

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

の署名は、boolの戻り値の型と2つの入力パラメーターを示しています

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

toInt

この関数は、文字列をintに変換します。

構文

String.toInt string_value

関数のシグネチャをチェックするには、elmREPL-に次のように入力します。

> 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

この関数は、文字列をfloatに変換します。

構文

String.toFloat string_value

関数のシグネチャをチェックするには、elmREPL-に次のように入力します。

> 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

elmREPLに続く関数型のシグネチャをチェックするには-

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

シグニチャは、戻り値の型として文字列を示し、文字の型として入力を示します

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

toList

この関数は、文字列を文字のリストに変換します。

構文

String.toList string_value

関数のシグネチャをチェックするには、elmREPL-に次のように入力します。

> 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

関数のシグネチャをチェックするには、elmREPL-に次のように入力します。

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

シグニチャショー関数は文字のリストを返し、文字列を入力します。

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

toUpper

この関数は、文字列をすべて大文字に変換します。

構文

String.toUpper String_value

関数のシグネチャをチェックするには、elmREPL-に次のように入力します。

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

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

toLower

この関数は、文字列をすべて小文字に変換します。

構文

String.toLower String_value

関数のシグネチャをチェックするには、elmREPL-に次のように入力します。

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

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

トリム

この関数は、文字列の両側の空白を取り除きます。

構文

String.trim String_value

関数のシグネチャをチェックするには、elmREPL-に次のように入力します。

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

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

フィルタ

この関数は、入力文字列から文字のセットをフィルタリングします。テストに合格した文字のみを保持します。

構文

String.filter test_function string_value

関数のシグネチャをチェックするには、elmREPL-に次のように入力します。

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

署名は、フィルターが2つの入力パラメーターを受け取り、文字列を返すことを示しています。最初のパラメーターは、入力Charを持ち、Boolを返す関数です。

この例では、パラメーターとしてChar.isUpperをフィルターメソッドに渡します。以下に示すように、すべて大文字を返します。

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

地図

この関数は文字列を受け取り、文字列内のすべての文字を変換します。

構文

String.filter mapping_function string_value

関数のシグネチャをチェックするには、elmREPL-に次のように入力します。

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

次の例では、文字oを@ −に置き換えます。

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

リスト、タプル、およびレコードのデータ構造を使用して、値のコレクションを格納できます。

この章では、Elmでリストを使用する方法について説明します。

リストは同種の値のコレクションです。リスト内の値はすべて同じデータ型である必要があります。

変数を使用して値を格納するときは、次の制限を考慮してください。

  • 変数は本質的にスカラーです。つまり、宣言時に変数が保持できる値は1つだけです。これは、プログラムにn個の値を格納するには、n個の変数宣言が必要になることを意味します。したがって、より多くの値のコレクションを格納する必要がある場合、変数の使用は実行できません。

  • プログラム内の変数にはランダムな順序でメモリが割り当てられるため、宣言された順序で値を取得/読み取ることが困難になります。

構文

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

次の例は、Elmでリストを使用する方法を示しています。elmREPLでこの例を試してください-

> 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:リストa-> Bool リストが空かどうかをチェックします
2 逆:リストa->ブール 入力リストを逆にします
3 長さ:リストa-> Int リストのサイズを返します
4 最大:リスト比較可能->多分。多分比較可能 最大値を返します
5 最小:比較可能なリスト->多分。多分比較可能 最小値を返します
6 合計:リスト番号->番号 リスト内のすべての要素の合計を返します
7 製品:リスト番号->番号 リストが空かどうかをチェックします
8 ソート:比較可能なリスト->比較可能なリスト リストを昇順で並べ替えます
9 concat:リスト(リストa)->リストa たくさんのリストを1つにマージします
10 追加:リストa->リストa->リストa 2つのリストをマージします
11 範囲:Int-> Int-> List Int 最初から最後までの数値のリストを返します
12 フィルタ:(a-> Bool)->リストa->リストa 入力リストから値のリストをフィルタリングします
13 頭:リストa->たぶん。たぶんa リストから最初の要素を返します
14 テール::リストa->多分。多分(リストa) 頭を除くすべての要素を返します

isEmpty

リストが空の場合、この関数はtrueを返します。

構文

List.isEmpty list_name

関数のシグネチャをチェックするには、elmREPL-に次のように入力します。

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

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

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

逆行する

この関数はリストを逆にします。

構文

List.reverse list_name

関数のシグネチャをチェックするには、elmREPL-に次のように入力します。

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

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

長さ

この関数は、リストの長さを返します。

構文

List.length list_name

関数のシグネチャをチェックするには、elmREPL-に次のように入力します。

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

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

最大

この関数は、空でないリストの最大要素を返します。

構文

List.maximum list_name

関数のシグネチャをチェックするには、elmREPL-に次のように入力します。

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

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

最小

この関数は、空でないリストの最小要素を返します。

構文

List.minimum list_name

関数のシグネチャをチェックするには、elmREPL-に次のように入力します。

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

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

この関数は、リスト内のすべての要素の合計を返します。

構文

List.sum list_name

関数のシグネチャをチェックするには、elmREPL-に次のように入力します。

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

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

製品

この関数は、リスト内のすべての要素の積を返します。

構文

List.product list_name

関数のシグネチャをチェックするには、elmREPL-に次のように入力します。

<function>  : List number ->  number

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

ソート

この関数は、リスト内の値を最低から最高にソートします。

構文

List.sort list_name

関数のシグネチャをチェックするには、elmREPL-に次のように入力します。

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

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

concat

この関数は、一連のリストを1つのリストに連結します。

構文

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

関数のシグネチャをチェックするには、elmREPL-に次のように入力します。

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

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

追加

この関数は、2つのリストをまとめます。

構文

List.append [list_name1] [list_name2]

関数のシグネチャをチェックするには、elmREPL-に次のように入力します。

> 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

範囲

この関数は、すべての要素が1ずつ増える番号のリストを作成します。リストに含まれるべき最小数と最大数が関数に渡されます。

構文

List.range start_range end_range

関数のシグネチャをチェックするには、elmREPL-に次のように入力します。

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

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

フィルタ

この関数は、入力リストから値のセットをフィルタリングします。テストに合格した値のみを保持します。

構文

List.filter test_function input_list

関数のシグネチャをチェックするには、elmREPL-に次のように入力します。

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

次の例では、入力リストからすべての偶数をフィルタリングします

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

この関数は、入力リストから最初の要素を返します。

構文

List.head input_list

関数のシグネチャをチェックするには、elmREPL-に次のように入力します。

> 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

この関数は、リストの最初以降のすべての要素を返します。

構文

List.tail input_list

関数のシグネチャをチェックするには、elmREPL-に次のように入力します。

> 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)

短所演算子の使用

短所演算子(::)は、リストの先頭に要素を追加します。

> 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でリストが不変かどうかを確認しましょう。値1と連結された最初のリストmyListは、新しいリストを作成し、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の他のタイプと同様に不変です。

構文

(data1,data2)

簡単な例を以下に示します-

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

以降のセクションでは、さまざまなタプル操作について学習します。

最初

この操作は、タプルから最初の値を抽出します。

構文

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

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

2番目

ザ・ second タプル操作は、タプルから2番目の値を抽出します。

構文

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つの数値を持つタプルを取り、それらの合計を返します。

破壊

破棄には、タプルを個々の値に分割することが含まれます。3つ以上の要素を持つタプル内の個々の値にアクセスするには、destructuringを使用します。ここでは、タプルの各値を異なる変数に割り当てます。_を使用すると、無視またはスキップされる値のプレースホルダーを定義できます。

> (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句で変数abcを宣言し、in句を使用してそれらにアクセスしています。

Elmのレコードデータ構造を使用して、データをキーと値のペアとして表すことができます。レコードを使用して関連データを整理し、データに簡単にアクセスして更新できるようにすることができます。Elmレコードは、JavaScriptのオブジェクトに似ています。レコード内のデータ要素はフィールドと呼ばれます。

レコードの定義

次の構文を使用してレコードを定義します-

構文

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

レコードには、複数のタイプのデータを格納できます。レコード内のフィールド名は、Elm識別子に名前を付けるための一般的な規則に準拠している必要があります。

レコード値へのアクセス

次の構文を使用して、レコード内の個々のフィールドにアクセスします。

構文

record_name.fieldname

または

.fieldname record_name

ElmREPLで次のことを試してください-

> 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]

ElmREPLで以下を試してください-

> [{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}

ElmREPLで以下を試してください-

> 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

次の例では、レコードの複数のフィールドを更新します。ElmREPLで以下を試してください-

> 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}

ElmREPLで以下を実行します-

> 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プログラミング言語は次の方法でエラーを処理します-

  • MayBe
  • Result

多分

アプリケーションの検索機能について考えてみましょう。検索キーワードが見つかった場合、検索関数は関連データを返します。それ以外の場合は何も返しません。このユースケースは、MayBeタイプを使用してElmに実装できます。

構文

variable_name:MayBe data_type

タイプMayBeの変数には、次のいずれかの値を含めることができます。

  • just some_Value-これは、有効なデータがある場合に使用されます。

  • なし-値が存在しないか不明な場合に使用されます。他のプログラミング言語では、nullに相当するものはありません。

次の例は、変数と関数でMayBe型を使用する方法を示しています。

Step 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

Step 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 
      

関数は、関数に渡された値がインドか中国かスリランカかをチェックします。パラメータの値がこれらのいずれにも一致しない場合、何も返しません。

結果

アプリケーションが何らかの条件を検証し、条件が満たされない場合にエラーを発生させる必要がある例を考えてみましょう。結果タイプを使用してこれを実現できます。アプリケーションが明示的にエラーを発生させ、問題の詳細を返したい場合は、結果タイプを使用する必要があります。

構文

結果タイプ宣言は、エラーのデータ型(通常は文字列)と、すべてがうまくいった場合に返される結果のデータ型の2つのパラメーターを取ります。

type Result error_type data_value_type
= Ok data_value
| Err error_message

結果タイプは、次のいずれかの値を返します-

  • Oksome_value-返される結果を表します

  • Err-期待される条件が満たされない場合に返されるエラーメッセージを表します。

イラスト1

ElmREPLで次の例を試してください-

> 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関数は整数値を返します。パラメータが数値でない場合、関数はエラーを返します。

イラスト2

次の例では、年齢をパラメーターとして受け入れます。この関数は、0〜135の場合は経過時間を返し、それ以外の場合は適切なエラーメッセージを返します。

Step 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

Step 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は、Model-View-Controllerパターンに似たアーキテクチャパターンを使用します。

以下は、Elmアーキテクチャの4つの主要部分です。

  • Model
  • View
  • Message
  • Update

Elmアーキテクチャはどのように機能しますか

ザ・ modelアプリケーションの状態が含まれます。たとえば、アプリケーションが顧客のリストを表示する場合、状態には各顧客データが含まれます。見栄えのする方法で状態を表示するには、view/ htmlを生成する必要があります。ユーザーがボタンを押すかフォームにデータを入力してビューを操作すると、ビューは次のようなシグナルを生成します。messages。メッセージはに渡されますupdateメッセージを評価し、適切なアクションを実行するメソッド。したがって、updateメソッドは新しいモデルを生成します。

新しいモデルは新しいビューを生成します。このビューは、ユーザーからシグナルメッセージへの新しい対話につながり、それが機能の更新につながります。さらに、この関数は新しいモデルを作成します。したがって、上の図に示すように、このサイクルが繰り返されます。

モデル

モデルはアプリケーションの状態を扱います。モデルを定義するための構文を以下に示します-

-- Model syntax

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

モデルを作成するには、最初に、必要なすべてのプロパティを含むテンプレートを作成する必要があります。各プロパティは、アプリケーションの状態を指定します。

見る

ビューは、アプリケーションの状態を視覚的に表したものです。ビューは、データを取得してそこからWebページを生成する方法を知っています。ユーザーがビューを操作すると、ユーザーはメッセージを生成して状態を操作できます。ビューを定義するための構文を以下に示します-

--View Syntax
view model =some_implementation

メッセージ

メッセージは、アプリケーションの状態を変更するためのユーザーからの要求です。メッセージはパラメータとして更新関数に渡されます。

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

構文はタイプメッセージを示しています。elmアプリケーションは、渡されたメッセージに基づいて状態を編集します。これらの決定は、更新メソッドで行われます。

更新

更新関数は、パラメーターとして渡されたメッセージを解釈し、モデルを更新します。

--Update Syntax
update Message_type model =
   some_implementation

更新機能は Message and Model as parameters.

A package manager is a command-line tool that automates the process of installing, upgrading, configuring, and removing packages in your application.

Just like JavaScript has a package manager called npm, elm has a package manager called elm-package.

The package manager performs the following three tasks −

  • Installs all dependencies that an elm application need
  • Publishes custom packages
  • Determines the version of your package when you are ready to publish and update.

Elm Package Manager Commands

The following table lists down the various Elm package manager commands −

Sr. No. Command Syntax Description
1 install elm-package install Installs packages to use locally
2 publish elm-package publish Publishes your package to the central catalog
3 bump elm-package bump Bumps version numbers based on API changes
4 diff elm-package diff Gets differences between two APIs

In order to publish your package, you need to host source code on GitHub and have the version properly labeled with a git tag. Following illustration shows how to use elm-package manager to pull an external dependency.

Illustration - Installing svg package

In this example, we will see how to integrate Scalable Vector Graphics(SVG) into an elm application.

Step 1 − Create a folder elmSvgApp

Step 2 − Install svg package using the following command −

elm-package install elm-lang/svg

Step 3 − Install Create a SvgDemo.elm file and type the content given below. We import Svg module to draw a rectangle of 100x100 dimension and fill the colour red.

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"
      ]
      []
   ]

Step 4 − Now build the project using elm make .\SvgDemo.elm. This will generate an index.html as shown below −

Message is a component in the Elm architecture. These components are generated by the View in response to the user's interaction with the application's interface. Messages represent user requests to alter the application's state.

Syntax

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

llustration

The following example is a simple counter application. The application increments and decrements the value of a variable by 1 when the user clicks on the Add and Subtract buttons respectively.

The application will have 4 components. The components are described below −

Message

The messages for this example will be −

type Message = Add | Subtract

Model

The model represents the state of the application. In the counter application the model definition is given below; the initial state of counter will be zero.

model = 0

View

The view represents the visual elements of the application. The view contains two buttons ( + ) and ( - ) . The messages Add and Subtract are generated by the View when the user clicks on the + and - buttons respectively. The modified value of the model is then displayed by the View.

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

Update

This component contains code that should be executed for each message generated by the view. This is shown in the example below −

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

Putting it all together

Step 1 − Create a folder MessagesApp and file MessagesDemo.elm

Step 2 − Add the following code in elm file −

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
   }

Step 3 − Execute the elm make command in terminal. The elm make command compiles the code and generates an HTML file from the .elm file created above.

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

Step 4 − Open the index.html and verify the working as shown below −

Elm - Commands

In the previous chapters, we discussed the various components of Elm architecture and their functions. The user and the application communicate with one another using Messages.

Consider an example, where the application needs to communicate with other components like an external server, APIs, microservice, etc. to serve the user request. This can be achieved by using Commands in Elm. Messages and commands are not synonymous. Messages represent the communication between an end user and the application while commands represent how an Elm application communicates with other entities. A command is triggered in response to a message.

The following figure shows the workflow of a complex Elm application −

The user interacts with the view. The view generates an appropriate message based on the user's action. The update component receives this message and triggers a command.

Syntax

The syntax for defining a command is as given below −

type Cmd msg

The message generated by the view is passed to the command.

Illustration

The following example makes a request to an API and displays the result from the API.

The application accepts a number from the user, passes it to the Numbers API. This API returns facts related to the number.

The various components of the application are as follows −

Http Module

The Http Module of Elm is used to create and send HTTP requests. This module is not a part of the core module. We will use the elm package manager to install this package.

API

In this example, the application will communicate with the Numbers API – "http://numbersapi.com/#42".

View

The application's view contains a textbox and a button.

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

The Model represents the value entered by the user and the result that will be returned by the API.

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

Message

The application has the following three messages −

  • ShowFacts
  • Input
  • NewFactArrived

Upon clicking the Show Facts button, ShowFacts message is passed to the update method. When the user types some value in the textbox, the Input message is passed to update method. Finally, when the Http server response is received, the NewFactArrived message will be passed to update.

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

Update

The update method returns a tuple, which contains the model and command objects. When the user clicks on the Show Facts button, the Message is passed to the update which then calls the 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)

Helper Function

The helper function getRandomNumberFromAPI invokes the NumbersAPI and passes to it the number entered by the user. The result returned by the API is used to update the model.

getRadmonNumberFromAPI : String->Cmd Msg
getRadmonNumberFromAPI newNo =
   let
      url =
         "http://numbersapi.com/"++newNo
   in
      Http.send NewFactArrived (Http.getString url)
Sr. No. Method Signature Description
1 Http.getString getString : String -> Request String Create a GET request and interpret the response body as a String.
2 Http.send send:(Result Error a -> msg) -> Request a -> Cmd msg Send a Http request.

main

This is the entry point of the Elm project.

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

Putting it all together

Step 1 − Create folder CommandApp and file CommandDemo.elm.

Step 2 − Install http module using command elm package install elm-lang/http.

Step 2 − Type the contents for CommandDemo.elm as shown below −

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)

Step 4 − Fire the command.

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

This will generate the html file as shown below.

Elm - Subscriptions

In the previous chapter, we discussed that a View interacts with other components using Commands. Similarly, a component (E.g. WebSocket) can talk to a View using Subscriptions. Subscriptions are a way that an Elm application can receive external inputs like keyboard events, timer events and WebSocket events.

The following figure explains the role of Subscriptions in an Elm application. The user interacts with an Elm application via messages. The application given uses WebSocket and it has two modes of operations −

  • Send client-side data to socket server via Command
  • Receive data anytime from the socket server via Subscription

Syntax

The syntax for defining a subscription is given below −

type Sub msg

Illustration

Let us understand subscriptions using a simple example.

In the example given below, the application sends a message to the server. The server is an echo server, which responds to the client with the same message. All the incoming messages are later displayed in a list. We will use WebSocket (wss protocol) to be able to continuously listen for messages from the server. The WebSocket will send user input to the server using Commands while it will use Subscription to receive messages from the server.

The various components of the application are given below −

Echo server

The echo server can be accessed using the wss protocol. The echo server sends back user input to the application. The code for defining an echo server is given below −

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

Model

The Model represents user input and a list of incoming messages from the socket server. The code for defining the Model is as given below −

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

Messages

The message type will contain Input for taking text input from user. The Send message will be generated when user clicks the button to send message to WebSocket server. The NewMessage is used when message arrives from echo server.

type Msg
   = Input String
   | Send
   | NewMessage String

View

The application's view contains a textbox and a submit button to send user input to the server. The response from the server is displayed on the View using a div tag.

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

The update function takes the message and the model components. It updates the model based on the message type.

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)
Sr. No. Method Signature Description
1 WebSocket.listen listen : String -> (String -> msg) -> Sub msg Subscribes to any incoming messages on a websocket.
2 WebSocket.send send : String -> String -> Cmd msg Sends a wss request to a server address. It is important that you are also subscribed to this address with listen. If you are not, the web socket will be created to send one message and then closed.

Subscription

The subscription function takes in the model object. To receive the messages from WebSocket server, we call WebSocket.listen passing in the message as NewMessage. When a new message comes from the server, the update method is called.

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

main

The main function is the entry point to the elm application as shown below.

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

Putting it all together

Step 1 − Create a directory,SubscriptionApp and add a file,SubscriptionDemo.elm to it.

Step 2 − Add the following contents to SubscriptionDemo.elm file −

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 ]

Step 3 − Install the websockets package using elm package manager.

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

Step 4 − Build and generate index.html file as shown below.

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

Step 5 − Upon execution, the following output will be generated −