##ごあいさつ
皆さんはじめまして。@enmaと申します。
Elmに興味があってここをご覧になられている方と、そうでない方もおられると思いますが、Elm Advent Calendar 2017の16日目の記事です。
一応断っておきますと、筆者はこれまで関数型言語での実装経験はありませんし、Webページ制作の経験もほとんどありません。しかしながら、Elmは純粋関数型言語としての魅力があり、またWebページ作成の観点からもかなり実用的な言語であると思いました。
初心者なりにElmの魅力を伝えられれば、更なるコミュニティの拡大にも繫がりますし、今回僭越ながら**「Elm初心者がElm Packagesを使えるようになるまで」**というタイトルで書かせて頂いております。どうぞ続けてご覧頂けると嬉しいです。
##Elmことはじめ
筆者はこれまで関数型プログラミングに縁が無く、@ababup1192さんの記事をきっかけにElmの学習を始めました。今回は、これまで筆者が学習した内容と、Elmのコードを動作させる環境構築の手順を説明します。その後、Ellieと呼ばれるオンライン上のWebサービスを使って、Elmのプログラムを動作させるまでが記事の内容となります。
Elmは、HTMLやJavaScript、CSSで構成されたWebアプリケーションを、Elmのみで簡単に生成することができるプログラミング言語です。
elm-make
を実行することで、Elmで書かれたファイル(.elm)の依存関係を解決して(すなわちelm-package.json
の作成が為されて)コンパイルが行われ、HTMLやJavaScriptのファイルを生成することが可能です。
筆者は恥ずかしながらHTMLやJavaScriptが使えないので、Elmさえ覚えれば(痒い所に手は届くかは置いておいて)Webアプリが作れるという点はかなり魅力的です。
※ CSSに関しては、例えばelm-cssがありました。また新しく出された@arowMさんの記事も参考になりそうです。
また、Elmは以下のような特徴を持っています。
・純粋関数型言語であり、静的型付き言語である
・型についてはかなり厳密なイメージ(その分実行時エラーが起こりにくい)
・他言語と比較して、シンプルなコード記述で求める機能の実装が可能
・型推論、型検査の機能を持ち、Haskell由来の強力なパターンマッチを有する
Elmは現在、The Elm Architectureという設計思想に則りWebアプリケーションを構成するのが定石とされています。リリースバージョンはまだ0.18ということもあって、破壊的なパラダイムシフトが行われる可能性もありますが、The Elm Architectureはシンプルかつ明快な思想であることから、廃止される可能性は低いと思っています。
The Elm Architectureは、beginnerProgram
を使う方針とprogram
を使う方針の2通りがあります(詳しくはElm PackagesのProgramの項を参照)。筆者は取っ掛かりとして、今回はbeginnerProgram
を使う方法を中心に学習しました。
beginnerProgramを使用するには、model/view/msg/updateという4種類の関数と型を用意します。
beginnerProgram
: { model : model, view : model -> Html msg, update : msg -> model -> model }
-> Program Never model msg
それぞれの関数/型のイメージは、Webアプリケーションの場合
・model
:Webアプリを構成する要素を定義し、それらの状態を示す(したがって初期状態の定義が必要)
・view
:modelをhtmlに変換する関数
・msg
:何らかのイベント(例えばボタンクリック)を示す
・update
:msgが投げられた際に、msgと元のmodelから新たなmodelを作成する
です。Elmの構文はHaskellライクのようですが、Haskell未経験の方はおそらく私同様、少し面食らうでしょう。まずは、Elmの文法/構造についてWeb上の入門記事を見ながら、目で追って確認していくのが良いです。
文法学習にはおそらくElmチートシートを見るのが手っ取り早いですが、英語に抵抗のある方はElmチュートリアル(日本語版)の基本の項や、プログラミング言語Elmの薄い本のPartIIの項を眺めてみてください。
その後、例えば@mather314さんの記事「[Elm 0.18 入門 (1)カウントアプリを作ってみる]
(https://qiita.com/mather314/items/e9e08960d91b187652e5)」を読めば導入が割とスムーズです。
更には、Elm Packages内のPopular Packagesを徐々に見ていくとElmはデフォルトで豊富な機能を用意してくれている事が分かります。パッケージをimport
すれば、パッケージの中で既に用意されている関数を利用することが出来ます。
Elm Core LibrariesやHTML for Elmはおそらく必修に近いレベルであり、Webページ作成を行う際にこれらは使いこなせるようになっておく必要があると感じました。
Elmの文法については割愛させて頂きますが、個人的に少し悩み、つまづきポイントだと感じた点を以下にいくつか挙げました。
➀ typeとtype aliasの使い所のイメージ
➁ Elm Packagesの個々のパッケージの中で定義されている関数の見方
➂ 複数の型や値を持つものから、特定のものを取り出す方法
➀ typeとtype aliasの使い所のイメージについて
type
は新しい型を定義したい時に使う、type alias
はレコード型の定義もしくは既存の型に別名を付けたい時に使う、ということで意味は理解できるのですが、同じ"type"という語を使っていることもあり少し混乱しました。混乱の元となったのはおそらく、ユニオン型(Union Types
)があるせいです。ユニオン型は、以下のように型の集約が可能です。
type Fruits = Orange | Melon | Apple
コード内の|
記号が"OR"という意味ではないということに注意してください。上の例は、Fruits
がOrange
かMelon
かApple
のいずれかの値を取り得るという定義です。ユニオン型は列挙した値のいずれかになるというイメージをしっかりと持った方が、理解がしやすくなると思いました。
ユニオン型ではない型定義の場合、
--type 型名 = データ構築子 (定義に必要な既存の型)...
type Msg = Get String
のように、型名とデータ構築子は大文字から始まる必要があること、必ず他と被らない新しいデータ構築子も定義される必要があることに注意して新たな型を定義してください。
また、type alias
で定義された型変数は以下のようなイメージを持つと分かりやすいです。
-- 整数型 Intに"金額"という意味を付加することで扱いやすくする
type alias Amount = Int
-- レコード型を用いて"Player"型に"id"と"name"という複数の属性を付加させる
type alias Player =
{ id : Int
, name : String
}
➁ Elm Packagesの個々のパッケージの中で定義されている関数の見方について
ひどいものだと->
が何個も登場するものがあります。
lazy3 : (a -> b -> c -> Html msg) -> a -> b -> c -> Html msg
どんなに->
が多くても結局、戻り値は一つしかないので
・右端の型にたどり着くまでの型は全て引数とみなす
・パイプ演算子や部分適用などを駆使して、戻り値が右端の最後の型になるように ->
で繋げて型を定義する
という見方が良いかなと思われます。
➂ 複数の型や値を持つものから、特定のものを取り出す方法について
名前付き関数の定義の際、最初の行には関数のシグネチャを書きます(関数の意図を明確にするために記述することを推奨)。次の行で関数名 引数1 引数2 ... = 式
という構造を用いて、関数内の全体をifで切り分ける代わりに、特定の引数を指定して関数を分割定義できます。このような書き方はパターンマッチと呼ばれ、意外と習熟が必要なところで難しいです。
type alias Amount =
Int
type Dollar
= Dollar Amount
-- "Dollar"型から"Amount"型を取り出すmoney関数
money : Dollar -> Int
money (Dollar amount) =
amount
case
式によるパターンマッチ以外にも、上記のように引数によるパターンマッチも可能です。money関数の定義の2行目で、"amount"という引数を用いて"Dollar"型から"Amount"型を取り出すことを実現しています。上記を書くに当たり、@ababup1192さんの記事をはじめ、株式会社ガラパゴスさんの記事や@7shiさんの記事も参考にさせて頂きました。
※ type A = Hoge Int
の形なら引数のパターンマッチが可能だが、type B = Hoge Int | Foo String
の場合case
式を必ず使わないといけないので注意すべき、とのご指摘を@ababup1192さんから頂きました。ありがとうございます。
##コードの実行環境について
それでは、実際にコードを実行する環境についての話に進みます。
Elmのコードを実行するには、まずNode.jsのインストールが必要です。Node.jsはサーバーサイドJavaScriptの実行環境です。Node.jsはNode.jsのモジュールを管理するためのツール「npm」を用いてnpm i
でインストールします(npm i
が通らない場合、npm自体のヴァージョンが古い可能性があります。筆者はnpmのバージョンが古かったのでnpm install -g npm
で上げました)。
また、Elmのヴァージョンは0.18.0
です(Elm -v
コマンドで確認できます)
※1.筆者の使用PCはSurface Pro4、OSはWindows10 Pro RS2です
※2.万が一npm
が使えない場合、MacとWindowsは、公式サイトからインストーラが提供されていますのでそちらを使用してください
インストールできたかどうかは、コマンドライン上でelm -v
やelm make -h
を叩いたりして、何らかの実行結果が返ってくれば成功です。筆者の環境ではGit bash、Command prompt、WSL(Windows Subsystem for Linux)でいずれも動作可能でした。
elm-package install elm-lang/html
でHtml
パッケージ(パッケージはPythonで言うところのモジュールのイメージです)をインストールした後、適当なコード(例えば以下)を書いてelm-make hello.elm
を実行すればコンパイル成功です。
import Html exposing (text)
main =
text "Hello World"
また、記述したコードが特定のパッケージに依存している場合、elm-package.json
が置いてあるフォルダ上でelm-package install
を実行すれば、elm-package.json
に記述してある依存ライブラリを自動でインストールしてくれます。
##コードの記述環境について
Elmを書くエディタはVisual Studio Code
を使用しています。VS CodeにはElmプラグインがあり、導入することでElmが非常に見やすく、書きやすくなります。中でもelm-format
という機能はElmの独特な(or Haskellライクな)コードの整形を半自動で行ってくれるのでおすすめです。
npm
が使えれば導入は問題ないと思われますが、例えばプロキシでネットワークが制限されている場合、npm
を使ったインストールができないことがあります。Windows
の場合は、elm-format.exe
がリリースされています(以下はファイルのリンクです)
https://github.com/avh4/elm-format/releases/download/0.7.0-exp/elm-format-0.18-0.7.0-exp-win-i386.zip
elm-make.exe
やelm-repl.exe
があるフォルダにelm-format.exe
を格納したあと(筆者はGit bashを入れていたので、VS Code上でwhich
コマンドを実行してelm-make.exe
が置いてある場所を確認しました)、ワークスペース設定のパス指定のところで
"elm.formatCommand":"elm-format"
と記述すれば、新たにパスを通さずともShift+Alt+F
コマンドによるコード整形が機能するようになります。
書いたコードの実行結果は、VS Codeでも確認することは出来ますが、他にもElmに標準で用意されているelm-reactor
(HTTPサーバーを通して、書いたプログラムの実行結果をブラウザを見ながら確認できる)や、対話環境としてのelm-repl
(式を実行して値や型の確認が可能)があります。
また、筆者は勉強する中でEllie というElm専用のWebサービスがあることを知りました。
Ellieはオンライン上のElmのテキストエディタで、コードを書いてコンパイルすることで、Webページがどのように表示されるか確認することができます。Elmのパッケージ(Elm Packages)も追加できるので、小規模な開発環境としては有用だと思います。Pythonで言うところのJupyter Notebookに近い使い勝手の良さですね。詳しくは[Elm 0.18 入門 (1)カウントアプリを作ってみる]
(https://qiita.com/mather314/items/e9e08960d91b187652e5)のページを参考にしてください。
##Ellieを使ってElm Packagesのコードを実行してみる
試しにelm-colorpicker
というパッケージを使ってコードを書き、コンパイルを通してみましょう。Elm Packagesには有志が作成したパッケージが数多くあり、elm-colorpicker
もその中の一つです(日本だとジンジャーさんという方が数多くパッケージを公開されています(http://jinjor-labo.hatenablog.com/)
GoogleChromeでEllieを開いた後(筆者の環境では、IEだとうまく動作しませんでした)、左側のSearch for packagesでelm-colorpickerと入力し、パッケージをインストールしてください。その後、Elm PackagesのSearchにelm-colorpickerと入力し、パッケージの説明ページを見てください。Exampleという項におよその使い方が書かれてあります。これを参考にしながら、beginnerProgramを使ってEllie上でプログラムを実行してみましょう。
誤植を訂正しつつ、beginnerProgramを使ってEllie上で最低限動作するプログラムを以下に書きました。
module Main exposing (..)
import ColorPicker exposing (State, empty, view)
import Html exposing (Html, beginnerProgram)
import Color
main : Program Never Model Msg
main =
Html.beginnerProgram
{ model = init
, update = update
, view = view
}
type alias Model =
{ colour : Color.Color
, colorPicker : ColorPicker.State
}
init : Model
init =
{ colorPicker = ColorPicker.empty
, colour = Color.rgb 255 0 0
}
type Msg
= ColorPickerMsg ColorPicker.Msg
update : Msg -> Model -> Model
update message model =
case message of
ColorPickerMsg msg ->
let
( m, colour ) =
ColorPicker.update msg model.colour model.colorPicker
in
{ model
| colorPicker = m
, colour = colour |> Maybe.withDefault model.colour
}
view : Model -> Html Msg
view model =
ColorPicker.view model.colour model.colorPicker
|> Html.map ColorPickerMsg
ページの右上辺りにカラーピッカーが現れればコンパイル成功です。
本当は、Googleのcolorpickerのように、コンターだけではなくカラーコードも表示できるようにしたかったのですが、経験不足で今回は実装できませんでした。今後の課題とさせて頂きます。
##あとがき
Elm初心者として、Elm導入からサンプルコード実行までの流れを記事にしてみました。The Elm Architectureという分かりやすい設計思想を持ち、関数型言語として簡潔な記述が可能であるという点は十分魅力的なポイントです。教育的かつ実用的であり、周りの方にも勧めやすい言語である気がします。Elmをベースにして、関数型プログラミングについての知識を更に深めていきたいです。ここまで読んで頂き、ありがとうございました!