Elm の文法を勉強をする人の多くは Elm REPL (以下 REPL) を使っている場合が多いと思います。
ただし、型注釈 については REPL 上で記述しても I cannot handle type annotations.
というメッセージが出力されて無視されます。
REPL に頼らずコードを書いて都度コンパイルして確認したり、Elm Reactor を使ったりするのも 1つの手です。
ただ、HTML や Elm アーキテクチャを気にする必要があるので、型注釈に集中したい場合は少し不向きでしょう。
この記事ではファイルに型注釈 (と関数定義) を記述し、それを REPL からインポートする方法を紹介します 1 。
「もっと楽な方法があるよ」という場合は、コメントでのフォローや紹介記事の作成をしていただけると嬉しいです。
想定している読者
- Elm の文法を勉強中で、Elm アーキテクチャにあまり触れていない人。
- Elmガイドの 型を読む のコードを写経していたら「型注釈」のところで「REPL じゃ動かんやんけ!」となった人。
- 基礎からわかるElm P.58 を読んで「具体的に何すればええんや」となった人。
おおざっぱな手順
-
elm init
する。 -
src
ディレクトリ内に Elm ファイルを作成する。 - そのファイルで定義したモジュールを REPL 上でインポートする。
なお、エディタと REPL の切り替えコストは諦めます。
こまかい手順
elm init
の実行
テキトーなディレクトリを作成し、その中で elm init
します。
Knowing all that, would you like me to create an elm.json file now? [Y/n]
と訊かれたらそのままエンターします。
$ mkdir foo
$ cd foo
$ elm init
Hello! Elm projects always start with an elm.json file. I can create them!
Now you may be wondering, what will be in this file? How do I add Elm files to
my project? How do I see it in the browser? How will my code grow? Do I need
more directories? What about tests? Etc.
Check out <https://elm-lang.org/0.19.0/init> for all the answers!
Knowing all that, would you like me to create an elm.json file now? [Y/n]:
Okay, I created it. Now read that link!
ファイルの作成
src
ディレクトリが作成されているので、その中で次の 3つを記述したファイルを作成します。
-
module
文 - 型注釈
- 関数
ここでは次のような Hoge.elm
を作成したとします。
module Hoge exposing (..)
toString : Int -> String
toString n = String.fromInt n
elm repl
の実行
src
ディレクトリかその親ディレクトリで elm repl
を実行します。
$ elm repl
---- Elm 0.19.0 ----------------------------------------------------------------
Read <https://elm-lang.org/0.19.0/repl> to learn more: exit, help, imports, etc.
--------------------------------------------------------------------------------
>
モジュールのインポート
REPL 上で Hoge
モジュールをインポートします。
ここでは import Hoge
としていますが、関数呼び出しを簡便にするため import Hoge exposing (..)
とするのもいいでしょう。お好みで。
> import Hoge
>
正しくインポートされていれば toString
関数を実行できるはずなので試してみましょう。
> Hoge.toString 10
"10" : String
>
できました
ちなみにインポートに成功した後でファイルを変更した場合、その変更は自動で反映されます。
再度のインポートは不要です。
ここまで来たら後は ファイルに型注釈と関数を記述する → REPL 上で関数を呼び出す を繰り返していけば OK です。
おまけ:型注釈と関数定義が一致しない場合
これまでの話は型注釈と関数定義が一致していたので、特に問題は起きませんでした。
そのため「型注釈って結局何が嬉しいの?」という感想を抱いてしまうかもしれません。
記事の主旨からは逸れますが、型注釈と関数定義が一致しないコードではどうなるのか試してみましょう。
先の toString
関数の返す値を String
型のものから Int
型のものに変更します。
module Hoge exposing (..)
toString : Int -> String
toString n = n -- 型注釈に反して Int 型を返す
この状態で REPL 上で toString
関数を実行します。すると…
> Hoge.toString 10
-- TYPE MISMATCH -------------------------------------------------- src\Hoge.elm
Something is off with the body of the `toString` definition:
4| toString n = n
^
This `n` value is a:
Int
But the type annotation on `toString` says it should be:
String
Hint: Want to convert an Int into a String? Use the String.fromInt function!
>
怒られます
「toString
関数の型注釈 (type annotation
) によるとこの関数は Int
型ではなく String
型ですよ」という内容のメッセージです。
型注釈の内容が反映されていますね 2 。
このように、型注釈と関数定義が一致しない場合はそのことを検出して知らせてくれます。
なお、コンパイラは飽くまで「型注釈が正しい前提」で処理をします。
型注釈が誤っている場合でも関数に誤りがあるというメッセージになるので、その点は注意しておきましょう。
おしまり