その他の構文
if ~ then ~ else
case ... ofと同様にifも値を返します。JavaScriptの条件演算子(?)と同じです。
max a b = if a > b then a else b
また、if ~ then elseは次のように書くこともできます。
fizzbuzz n =
if | n % 15 == 0 -> "FizzBuzz"
| n % 5 == 0 -> "Buzz"
| n % 3 == 0 -> "Fizz"
| otherwise -> toString n
let ~ in
関数の中身が長くなる場合にはlet ~ inを使って、一時的に用いる変数を宣言することができます。 変数の宣言をletの後ろで行い、inの後ろに宣言した変数を使う処理を記述します。
distance a b =
let
-- 一時的な変数を宣言します
-- dx, dyは外部からアクセスできません
dx = b.x - a.x
dy = b.y - a.y
in
-- 計算結果を返します
sqrt (dx^2 + dy^2)
import ~ exposing ( ~ )
importにより、モジュールをインポートして使えるようになります。
import List len = List.length [1,2,3] -- 3
次のコードでは、モジュールに定義された関数を直接使えるようにしています。
import List exposing (length, reverse) import Html exposing (..) -- 全ての定義をインポート len = length [1,2,3] -- List.length reversed = reverse [1,2,3] -- List.reverse main = text (toString len) -- Html.text
Elmの組み込み標準モジュールやサードパーティのライブラリはパッケージカタログにて公開されています。 これらのうち、標準的な型や関数はimportなしで使えます。
関数型プログラミング
高階関数とラムダ式
次に、関数型プログラミングに慣れるために「関数を引数に取る関数」を見ていきましょう。以下は、リスト操作に頻出するList.map関数の使用例です。
-- List.map : (a -> b) -> List a -> List b -- toString : a -> String stringNumbers : List String stringNumbers = List.map toString [1,2,3] -- ["1","2","3"]
List.mapは、リスト中の全ての値に関数を適用し、新しいリストを生成します(JavaScriptのmap関数と同じです)。
型の記述についても慣れておきましょう。 (a -> b) -> List a -> List bは、aにInt型、bにString型を当てはめると、(Int -> String) -> List Int -> List Stringとなります。つまり、「第1引数にInt型をString型にする関数、第2引数にInt型のリストを取り、String型のリストを返す」関数になります。
次の例では、ラムダ式を使ってその場で関数を生成しています。
doubledNumbers = List.map (\n -> n * 2) [1,2,3] -- [2,4,6]
(\n -> n * 2)は、nを引数にとり、2倍して返す関数を表しています。
中置演算子は関数
+、*、::などの中置演算子は、通常の関数と同じように使うことができます。
-- (+) : number -> number -> number n = (+) 1 2 -- 1 + 2 と同じ
その他の演算子
|>はパイプ演算子とも呼ばれ、関数を連続して適用するときに便利な演算子です。 今すぐ書けるようになる必要はありませんが、時々出てくるので読めるようにしておきましょう。 以下の例において上下は同じ意味です。
import String exposing (..) len1 = length (repeat 3 (trim " HEY! ")) -- 12 len2 = " HEY! " |> trim |> repeat 3 |> length
また、trimからlengthまでを先に合成してから関数を適用するには>>を使います。
len3 = (trim >> repeat 3 >> length) " HEY! "
先ほど触れたように、これらの演算子の正体は関数です。それぞれの定義はパッケージカタログを参照してください。
Hello, world!
お疲れ様でした。以上でElmの基本的な構文説明は完了です。 今回は、ブラウザ上でElmプログラムを実行できる「Try Elm」を利用します。以下のコードを貼り付けて[Compile]ボタンを押してみてください。 無事、Hello, World!が画面に表示されているでしょうか。
import Html exposing (..) main : Html main = text "Hello, World!" -- Html.text : String -> Html
Elmでは、画面へのアウトプットをmain関数に記述します。 main関数は、Html、Signal Html、Element、Signal Elementという限られた型[4]のみが許されています。
Html.textは文字列を受け取りテキストノードを生成する関数です。少し味気ないと思いますので、試しに次のようにしてみましょう。
import Html exposing (..)
import Html.Attributes exposing (..)
url = "http://elm-lang.org/"
main : Html
main =
div
[]
[ h1 [style [("color", "green")]] [text "Hello, World!"]
, text "(written in "
, a [href url, target "_blank"] [text "Elm"]
, text ")"
]
ここで登場するdivやh1などは、全てelm-htmlパッケージが提供する関数です。
さてここまで、Elmの基本的な書き方について解説してきました。 慣れるまではいろいろ試してみるとよいでしょう。
次のページでは、FRPの基本となる「Signal」という機構を使って動く画面を作る方法を見ていきます。
[4]: これらの型を、モジュール名を省略しないで記述した場合、それぞれ、Html.Html、Signal Html.Html、Graphics.Element.Element、Signal Graphics.Element.Elementになります。
Graphics.ElementモジュールとHtmlモジュール
Elmは歴史的な理由から、Graphics.ElementとHtmlという2種類の基本的なモジュールを備えています。 前者はElmの登場した当時から存在するもので、色や位置を独自の関数で記述し、HTMLを隠蔽します。 一方、後者は「elm-html」パッケージにより導入され、HTMLタグを直接記述することができます。 今からElmでWebアプリケーションを作るのであれば、最初は後者のHtmlを使うことをお勧めします。 既存のWeb開発のノウハウをそのまま活かせますし、Twitter BootstrapなどのCSSフレームワークも難なく使えます。 とはいえ、Graphics.Elementも図形描画のための便利な関数が多数用意されており、まだまだ現役です。
