こんなエラーが出るんです。
I ran into something unexpected when parsing your code! - I am looking for one of the following things:
"'"
"|"
an equals sign '='
more letters in this name
whitespace
もしくはこれ
I ran into something unexpected when parsing your code! - I am looking for one of the following things:
a closing bracket '}'
a lower case name
whitespace
この記事の内容
recordを更新していて上記のようなエラーが出た理由
エラーになるコード
ネストしたレコードや他モジュールからrecordとってきて更新しようとしたときにエラーになります
type alias Point =
{ x : Int
, y : Int
}
type alias Model =
{ point : Point
, something : String
}
moveX : Int -> Model -> Model
moveX dx model =
{ model | point = { model.point | x = model.point.x + dx }}
これはネストしている場合です。PointとPointが入ったModelを作って、moveXでPointのxを変更しているコードです
特に問題ないように見えますが、このコードはコンパイルが通りません
model.point
の位置に一番上のエラーが出ます。コンパイルエラーなんですけど、最初なんでそうなるのかわかりませんでした。合法に見えるでんすよね
理由
recordのupdate構文には制限が掛かっていて、{
と|
の間には値(?)しか置けません
正確な用語はわからないんですけど1トークンしか置けない感じです
{ model | -- Ok
{ modelPoint | -- Ok
{ model.point | -- 関数適用はだめ
{ toRecord 1 "something" | -- 関数適用はだめ
{ AModule.record | -- 修飾名もだめ
Elm Discussを読んでみたんですが、
- あいまいさが残る
-
{ model.point |
の返却値はmodelとも読めるし(中のpointだけ更新する構文にも見える)、pointとも読める
-
- パースがちょっと大変
- 制限なくすとちょっと便利になるけど、言語の方向としてそっちが正しいか確信を持てないので変えません
- プロジェクトでやっぱりないとつらいってなったら報告してね
みたいな感じで、8日目のjinjorさんの記事で触れられている通りの雰囲気です
解決方法
上で言及したdiscussや関連するissueなどを読んでいただくのがいいと思うんですけど、いくつか解決策をあげておきます
moveX : Int -> Model -> Model
moveX dx model =
let
point = model.point
in
{ model | point = { point | x = model.point.x + dx }}
letで定義し直してしまう方法です。
簡単に置き換えるだけですが、ちょっとダサい気もしますね
moveX : Int -> Model -> Model
moveX dx model =
{ model | point = updatePoint model.point }
別の関数をかまします。そもそもネストしたものをその場で一気に変更するのは見づらいしやめようって感じです
あとは使い方わかっていないんですが、Lensってライブラリを使ってみるとか
追記
elm-monocleを使ってみた方がいるのでそちらをご参照ください
終わり
終わり。Elm Advent Calendar、今年は盛りだくさんなのでElm始めるにはいいタイミングかもしれませんね。
土曜も担当します