だいぶ前にElm触ってゲーム作った時はElmに色々と不満があったんだけど、あれからElmもだいぶバージョンアップして0.15.1ではエラーが人フレンドリーになったらしい。前回の不満がどれだけ解決されているか調べてみよう。
関数の引数の数間違いが謎の型エラーになったりする
module Test where import Html exposing (text) message2: String -> String -> String message2 world world2 = "Hello, " ++ world ++ " " ++ world2 main = text (message2 "World?" "World!")
というメッセージを表示するだけのコードを書いて、
main = text (message2 "World?")
と引数の数を間違うと、
The 1st argument to function `text` has an unexpected type. 8| text (message2 "World?") ^^^^^^^^^^^^^^^^^ As I infer the type of values flowing through your program, I see a conflict between these two types: String String -> String
8行目のここの引数がString
で無くString -> String
だぞと出る。素晴らしい。抜群に分かりやすくなっとる。
レコードのアップデートと追加構文を間違った時のパーサーのエラーが謎だった
main関数を
main = let world = {str = "World??"} world2 = {world | str2 = "World!!"} in text (message2 world2.str world2.str2)
とし、
world2 = {world | str2 = "World!!", str3 = "World?!"}
と許可されていない複数のフィールド追加を行うと、
11| world2 = {world | str2 = "World!!", str3 = "World?!"} ^ I am looking for one of the following things: a closing bracket '}' an expression an infix operator like (+) whitespace
とちゃんとここで'}'を閉じろと言う。素晴らしい。
型の宣言でのエラーや変数名の重複でその行番号を教えてくれない
message2: String -> String -> String2
とすると
Cannot find type `String2` 5| message2: String -> String -> String2 ^^^^^^^ Maybe you want one of the following? String
こう。
world = {str = "World??"} world = {world | str2 = "World!!"}
とすると
Naming multiple values `world` in a single let-expression makes things ambiguous. When you say `world` which one do you want? 11| world = {world | str2 = "World!!"} ^^^^^ Find all the values named `world` in this let-expression and do some renaming. Make sure the names are distinct!
こう。完璧ではないか。
乱数シードに現在時刻が欲しい
これはエラーメッセージとは関係ないのだが、乱数の初期化のために現在時刻が欲しかったのだが、その方法が良く分からなかった。
Elmの中だけでなんとかしようと思わないでportを使ってJavaScriptから供給すればいいらいいぞ。
portはElmとJavaScriptの間で値をやりとりする仕組みで、JavaScriptからsendされた値をElmのSignalとして受け取ることができる。
Elm.fullscreen(Elm.Test, {beginTime: Date.now()});
とJavaScriptからElmを起動する時に引数で与えた値を、
port beginTime: Float main = let world = {str = toString beginTime}
とportを介してもらえば良い。portってSignalじゃなくてもいいのね。たぶん不変な値限定だけど。
requestAnimationFrame対応
ElmのPongの例とかだと画面の更新はSignal.map inSeconds (fps 35)
とか使っていてタイマーベースだけど、できればこれはrequestAnimationFrameにしたい。
それにはelm-animation-frameを使えば良い。elm package install jwmerrill/elm-animation-frame
でパッケージをインストールし、
main = let frameNumSignal = Signal.map toString (Signal.foldp (+) beginTime AnimationFrame.frame) messageSignal = Signal.map (message2 "World?!") frameNumSignal in Signal.map text messageSignal
のようにAnimationFrame.frameをトリガに画面を更新すれば良いらしいぞ。
Elmイケているではないか
バージョンアップで着実に欠点が埋められている感じ。portを使ったJavaScriptとの連携がうまく使えれば、ゲーム作りにもいいかも。あとは良いIDEが欲しいよな。