前提としているElmのバージョンは0.18.0
。
- 実行環境
- リテラル
- 関数
- 型
- 構文
- モジュール
- Elmアーキテクチャ
- Htmlモジュール
- Tips
多分何種類かあると思うけど、代表的なモノを挙げる。
- elmにはREPL(Read-eval-print loop)という対話型評価環境がある。
- ようはターミナルでElmを試せる
- 複数行に跨るソースを打ち込む場合は、
\
を行末につける必要がある。
$ elm-repl
- 単純なアプリケーションを作る時につかう
- 外部JS、外部CSSの読み込みには対応していない
$ elm-reactor
- https://ellie-app.com/new
- オンラインでElmアーキテクチャを試せる
- ちゃんとしたアプリケーションを作る時に使う
-- Char
'a'
-- String
"Hello World!!"
-- Bool
True
False
-- Int(ただしREPLで打ち込むと、Int or Floatを表すnumberと解釈される
1000
-- Float
0.1
-- Tuple(値の組み合わせ。異なる型の組み合わせも可能。)
(1, "test")
- 関数は、同じ引数に対して常に同じ結果を返す
- 引数の状態を変えてはいけない。Elmはimmutableな世界なので、変えれないようになっている。
- 名前で呼び出して使う
- 1行目の
add : Int -> Int -> Int
は型注釈(Type Annotation)と言う - 以下は
Int
の引数を2つ受け取って、Int
の戻り値を返す関数
add : Int -> Int -> Int
add x y =
x + y
-- 呼び出し方
add 3 4
- 関数に渡して使う
- 最初に
\
を付ける - 以下は引数を2つ受け取って、足し合わせた結果を戻り値として返す関数
\x y -> x + y
- 定数となる
name : String
name =
"hoge"
-- 関数が引数
funcArg: (Int -> Int) -> Int -> Int
funcArg func x =
func x
-- 使い方
funcArg (\x -> 2 * x) 2
-- 関数が戻り値
funcReturn : (Int -> Int)
funcReturn =
\x -> 2 * x
-- 使い方
func =
funcReturn
func 2
- ある関数の結果を直接使って別の関数を呼び出したい場合に使う
()
を使う
multiply : Int -> Int -> Int
multiply x y =
x * y
add 3 (multiply 1 2)
- グループ化しないと、コンパイラに
add
の引数としてみなされてしまう。 - なおパイプ演算子を使うと
()
を外して見やすくすることができる。 - ListやMaybeの関数呼び出しなどでよく使う
2
|> multiply 1
|> add 3
- 他の言語で言う型パラメータとかのこと
- 関数をジェネリックにする
- 後述の
List
やMaybe
など型でも使われる
-- aとbが型変数な関数
switch : ( a, b ) -> ( b, a )
switch ( x, y ) =
( y, x )
- 関数はカリー化されていて部分適用ができるが、その話は以下を参照
- 既存の型に別名を付ける
- 型が明確になり、ソース全体の見通しが良くなる。
コレよりも
func : String -> String -> Int
こっちの方がわかりやすい
type alias Id =
String
type alias Name =
String
func : Id -> Name -> Int
- 複数の定数を1つの型で扱える
- 他の言語で言うenumのような感じ
type Color = Red | Blue | Green
-- 使い方
color =
Red
- 関連した情報を持つこともできる。ペイロードと呼ぶ。
type Color = Red | Blue | Green | RGB Int Int Int | NoneColor String
-- 使い方。
white =
RGB 255 255 255
type Text = Text String Color
-- 使い方
text =
Text "hoge" Red
type Bool = True | False
type Maybe a = Just a | Nothing
- キーバリューのセットを持つ
- type aliasを使うと、別名をコンストラクタ関数として使用できるようになる。
- immutableである。つまり属性の値を変更することはできず、変更するには新しいレコードを作ることになる。
-- 宣言
type alias User =
{ id : Int
, name = String
}
-- 使い方
user =
User 1 "hoge"
-- idを使いたい場合
user.id
-- 更新
newUser =
{ user | name = "new name" }
- 他の言語で言うCollection系で最も使うモジュール
- Coreでは他に、Dict, Set, Arrayがある
[1, 2, 3]
1 :: [2, 3]
1 :: 2 :: 3 :: []
- ここにドキュメントがあるので詳細はそちらを見れば良いので、ここでは幾つかの関数を紹介する
-- 型注釈
filter : (a -> Bool) -> List a -> List a
-- 使い方
List.filter (\x -> x % 2 == 0) [1, 2, 3]
- 要素の判定をする関数とListを渡すと、判定結果を満たす要素のみの新しいListを返す
(a -> Boolean)
を無名関数とすることが多い
-- 型注釈
map : (a -> b) -> List a -> List b
-- 使い方
List.map (\x -> toString x) [1, 2, 3]
- 要素を変換する関数とListを渡すと、Listの要素一つずつに関数を適用して要素を変換する
a
とb
は違うので、型を変えることもできる
- 他の言語で言う、
Option
Optional
とか - ありを
Just
、なしをNothing
で表す - null,nilとかundefinedがないのはMaybeのおかげ
- ユニオン型で定義されている
type Maybe a
= Just a
| Nothing
Just 1
- ここにドキュメントがあるので詳細はそちらを見れば良いので、ここでは幾つかの関数を紹介する
-- 型注釈
map : (a -> b) -> Maybe a -> Maybe b
-- 使い方
Maybe.map (\x -> toString x) (Just 1)
Maybe.map (\x -> toString x) Nothing
- 要素を変換する関数とMaybeを渡すと
- Justの場合は、要素に関数を適用して要素を変換
- Nothingの場合は、何もしない
-- 型注釈
withDefault : a -> Maybe a -> a
-- 使い方
Maybe.withDefault 0 <| Just 1
Maybe.withDefault 0 Nothing
- デフォルト値とMaybeを渡すと
- Justの場合は、要素を取り出す
- Nothingの場合は、デフォルト値を返す
return
はない- 式なので何かしらの値を返す
value = 1
-- ifはStringを返す
if value == < 0 then
"Negative number."
else if value == 0 then
"Zero."
else
"Positive number"
- 他の言語で言うパターンマッチ
- 式なので値を返す
- Union Typeと組み合わせると強力。Union Typeで定義した値が全て使われていない場合はコンパイラが怒ってくれる。
-- Union Type
---- ペイロードの値を取り出せる
type Color = Red | Blue | Green | RGB Int Int Int
color = Red
case color of
Red ->
"red"
RGB r g b ->
(toString r) ++ ":" ++ (toString g) ++ ":" ++ (toString b)
_ ->
"other"
-- List
---- 再帰で使える
case [1, 2] of
[] ->
""
head::tails ->
toString head
-- Maybe
case Just 1 of
Just x ->
x
Nothing ->
0
- 値を変数に入れて使えるようにする
- 見通しが良くなるので使うことが多い
let
a =
1 + 1
(b, c) =
( 2, 3 )
in
a * b * c
- 変数への再代入はできない。つまり以下はコンパイルエラーになる。
let
a =
1 + 1
a = 4
in
a
- 他の言語で言うforループ的なものはない
- 同等なことをやりたい場合は、Collection系に定義されている関数を使うか再帰を使う。
- モジュール = ファイルという考え方
- モジュール名はファイル名と一致していないといけない
Utils.StringUtils
モジュールなら、Utils/StringUtils.elm
というファイルを作る
func : String
func =
"hoge"
type Color = Red | Blue | Green
User =
{ name : String}
上記に対してモジュール宣言は以下となる。
-- 全てを公開する場合の宣言
module ModuleName exposing (..)
-- 特定の関数、型を公開する場合の宣言
module ModuleName exposing (func, Color(..), User)
Color
のみだとRed
などは公開されないので(..)
が必要となる。
import ModuleName
ModuleName.func
-- 別名を付ける
import ModuleName as Mod
Mod.func
-- 直接インポート
import ModuleName exposing(func)
func
- 関数は
別名.関数
、型はexposingで直接インポートが見やすい - 名前の競合はコンパイラに怒られる。
ここにデフォルトでインポートされているモジュールが載っている。 記述されているモジュールはインポートしなくても使える。
- Elmでフロントエンドアプリケーションを作るためのパターン
- 以下の4つが大きな要素
- Model
- Update
- View
- Msg(Message)
- アプリケーションの全ての状態(データ)を持つ
- アプリケーションで起きたコトを表す通知。union typeで定義する
- 起きた時に取得した値を持つ。(プルダウンメニューの変更値等の入力情報)
- Msgを受け取り、解釈してModelを更新して返す。
- 後続処理として何かやらしたい場合は、Msgを送信する。なければ
Cmd.none
を返す。
- Modelを使ってHTMLを生成する
-- モジュール宣言
module Main exposing (..)
-- Htmlモジュールをインポート
import Html exposing (program, Html, text)
-- Elmのエントリポイント
main : Program Never Model Msg
main =
program
{ init = init
, view = view
, update = update
, subscriptions = always Sub.none
}
-- Model
type alias Model =
{}
-- Msg
type Msg
= Hoge
-- アプリケーションの初期化関数
init : ( Model, Cmd Msg )
init =
( {}, Cmd.none )
-- Update
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
Hoge ->
( model, Cmd.none )
-- View
view : Model -> Html msg
view model =
text "Hello World!!"
- 次に何かをやらせたいことを書く
- なにもない場合は
Cmd.none
を使う - ここにドキュメントがある
- 外部入力(マウスイベント、キーボードイベント等)をアプリケーションに入れるためのサブスクリプション
- 今回は使用しないので
Sub.none
を設定している。
- viewを作るのに最初必要なのは以下の3つのモジュール。
- Html。要素。
- Html.Attributes。属性。
- Html.Events。イベント。
- これらを組み合わせてviewを生成する。
<button type="button" class="btn btn-primary">投稿</button>
- これをElmに変換してviewとすると以下となる。
import Html exposing (button, text)
import Html.Attributes exposing (class, type_)
view model =
button [ class "btn btn-primary", type_ "button" ] [ text "投稿" ]
要素、属性ともにそれぞれ関数の構造(引数及び戻り値)は同じなので、button要素とclass属性について見ていく。
-- 型注釈
button : List (Attribute msg) -> List (Html msg) -> Html msg
- 第1引数は、button要素の属性のListとなる
- 第2引数は、ネストする要素のListとなる
- 戻り値はHtml型
-- 型注釈
class : String -> Attribute msg
- 第1引数は、class属性の値
- 戻り値は
Attribute
型
- https://mbylstra.github.io/html-to-elm/
- その名の通り、HTMLからElmをソースを生成してくれるオンラインツール
- かなり便利
- Basicモジュール
- デフォルトインポートされている関数。よくある関数が揃っているので、ハンズオン中軽く眺めてみることをお勧めします。
- Style Guide
- Elm初心者でもできるprintデバッグ
- ブラウザのコンソールで見れるようになります。
- elm-format
- 使うと生産性が変わります。
- ElmとJavaScriptを組み合わせたアプリケーションの作り方
- ElmのPortでJSを使う。
- JSとのやり取りの仕方
- From JavaScript?
- 文法のJSとの対応表