※前編はこちらやで。
ハスケル子「引き続き、JavaScriptとElm・・・」
ハスケル子「そしてVue.jsもちょこっと比べてみましょう」
オブジェクト(のようなもの)
JavaScriptのオブジェクト
const takashi = {
displayName: "たかし",
age: 36,
height: 173,
weight: 73
};
ワイ「displayNameとかageとかが、プロパティいうやつやな」
ワイ「takashi.ageとかすると、プロパティの値にアクセスできんねん」
Elmのレコード
takashi =
{ displayName = "たかし"
, age = 36
, height = 173
, weight = 73
}
ワイ「Elmではレコードいうねんな」
ワイ「JSのオブジェクトとけっこう似てるな」
ワイ「displayNameとかageとかのことは」
ワイ「フィールドっていうんやな」
ワイ「JSと同じくtakashi.ageって書けばフィールドの値にアクセスできんねん」
オブジェクトのプロパティを更新
JavaScriptのオブジェクト
takashi.age = 37;
takashi.weight = 83;
ワイ「constで宣言した再代入不可なオブジェクトでも、プロパティは変更できてまうんやな」
Elmのレコード
newTakashi =
{ takashi | age = 37, weight = 83 }
ワイ「Elmでは全ての値が不変やからtakashi.age = 37みたいな上書きはできひんねん」
ワイ「せやから、1つ歳をとって10Kg太ったnewTakashiという新しいレコードを作る形になる」
ワイ「元々のtakashiは36歳のまま、別に存在すんねん」
ドキュメントの書き方
JavaScript (JSDoc)
/**
* @param {Number} num
* @param {String} str
* @return {String}
*/
function displayNumber (num, str) {
return num + str;
}
ワイ「関数の使い方が分かりやすいように」
ワイ「引数や戻り値の型をコメントで書いたりすんねんな」
ワイ「まぁ、実装とズレてても動くから、努力目標やけどな・・・」
Elmの場合は型で表現
displayNumber : Int -> String -> String
displayNumber num str =
String.fromInt num ++ str
ワイ「displayNumber : Int -> String -> Stringいうのは」
ワイ「このdisplayNumberいう関数は」
ワイ「引数としてInt型の値とString型の値を受け取って」
ワイ「戻り値としてString型の値を返す」
ワイ「そんな関数ですよ〜っていう」
ワイ「型注釈いうやつや」
ワイ「しかも、この型注釈で書いた通りに実装せえへんと」
ワイ「ちゃんとコンパイルエラーが出て教えてくれんねん」
ワイ「**TYPE MISMATCH(型の不一致)**です〜、言うてな」
ワイ「つまり、強制力のある注釈や!」
ビューの書き方
Vue.jsの場合(単一ファイルコンポーネント)
<template>
<div class="container">
<button>増やす</button>
<input type="text">
<button>減らす</button>
</div>
</template>
ワイ「ほぼhtmlやな」
ワイ「読みやすいな」
Elmの場合
view model =
div [ class "container" ]
[ button [] [ text "増やす" ]
, input [ type_ "text" ] []
, button [] [ text "減らす" ]
]
ワイ「このdivとかbuttonていうのがタグ名やね・・・?」
ハスケル子「まあそうなんですけど」
ハスケル子「タグ名というより、れっきとしたElmの関数です」
ハスケル子「関数なので───」
joinButton =
button [] [ text "参加する" ]
ハスケル子「───こんな感じで変数に格納すれば」
ハスケル子「それだけでコンポーネントみたいに使えますし」
commonButton buttonText =
button [] [ text buttonText ]
ハスケル子「↑こう、引数としてテキストを受け取る関数にすれば」
ハスケル子「propsを受け取って表示するタイプのコンポーネントもサクッと作れます」
ワイ「おお」
ワイ「コンポーネントも関数そのものやから、コードの中で自然に使えるな」
ハスケル子「そうなんです」
ハスケル子「リスト1の分だけ回してli要素を生成したい、なんて場合も簡単です」
イベントリスナ登録(のようなもの)
Vue.jsの場合
<button @click="incrementFunc">増やす</button>
<input type="text">
<button @click="decrementFunc">減らす</button>
ワイ「見たままやな」
ワイ「ボタンをクリックするとincrementFuncかdecrementFuncという」
ワイ「関数が実行されんねんな」
ワイ「関数はmethodsの中に書いとけばええんや」
Elmの場合
button [ onClick Increment ] [ text "増やす" ]
, input [ type "text" ] []
, button [ onClick Decrement ] [ text "減らす" ]
ワイ「こう書いておけば、このボタンをクリックした時に・・・?」
ハスケル子「IncrementまたはDecrementというメッセージが生み出されます」
ワイ「メッセージ・・・?」
ワイ「そのメッセージはどこで受け取るん?」
ハスケル子「状態の更新内容を定義するupdateっていう関数で受け取ります」
update msg model =
case msg of
Increment ->
{ model | int = model.int + 1 }
Decrement ->
{ model | int = model.int - 1 }
ハスケル子「Incrementというメッセージが来たら」
ハスケル子「model・・・つまりVuexでいうstoreのstateみたいなもんですね」
ハスケル子「要はmodelイコール状態です」
ハスケル子「そのmodelの中のintを1増加させます」
ハスケル子「メッセージがDecrementだった場合は1減らす感じですね」
ハスケル子「そして、それによって生成された新しいmodelを戻り値として返すって感じです」
ワイ「ほえ〜、新しいmodel、つまり新しい状態を返すと」
ワイ「それがリアクティブにビューに反映されるっていうこと?」
ハスケル子「そうです」
ワイ「そうなんやね〜」
ワイ「Elmって、VueとかReactみたいに仮想DOMを内蔵してたんやね」
ワイ「あとVuexやRedux相当の機能もか」
ハスケル子「そうです」
ハスケル子「っていうかVuexもReduxも、Elmの影響を受けてます」
ハスケル子「Elmというか、今みたいなThe Elm Architectureというパターンの影響ですね」
ハスケル子「しかもElmはとってもシンプルなので」
ハスケル子「学習コストが低くて、やめ太郎さんにピッタリです」
ワイ「どういう意味やねん」
ハスケル子「オンラインエディタでさっきのカウンタのサンプルコードを色々いじってみると」
ハスケル子「更に分かると思いますよ」
ワイ「やってみるわ」
ワイ「おおきにやで、ハスケル子ちゃん」
ハスケル子「Vue勉強しててもReact勉強してても」
ハスケル子「副作用を起こさないように、とか」
ハスケル子「外部の状態に依存しない純粋な関数・・・つまり参照透過的な関数を書こう、とか」
ハスケル子「色んなドキュメントに書いてあるんですよ」
ハスケル子「じゃあ、そういう風にしか書けないElmやりゃあいいんですよ」
ワイ「お、おう・・・」
ワイ「前向きに検討するわ・・・」
ワイ「っていうか、今回JSやVueと比較したおかげでElmの文法がかなり分かったから」
ワイ「普通に読み書きできそうやな・・・」
ワイ「やってみるで!」
〜おしまい〜
-
配列みたいなやつやで。 ↩