[Web フロントエンド] Elm に心折れ Mint に癒しを求める
こんにちは、 Elm
- Elm – A delightful language for reliable webapps
https://elm-lang.org/ - はじめに · An Introduction to Elm (Elm 公式ガイド日本語訳)
https://guide.elm-lang.jp/
Elm は関数型の小さな言語仕様を持つ altJS です。 Redux が影響を強く受けた ことでも有名ですね。 “No Runtime Exceptions” は魅力的ですし、何より興味深いのは The Elm Architecture です。
Redux にはあまりセンスを感じられなかったのですが、 The Elm Architecture はとても良さげに見えました。 Elm が持つ 代数的データ型 と パターンマッチ、状態の不変性、 レコードの部分更新式 などとうまく馴染み、簡潔に書きやすそうで、なにより読みやすそうだと思いました。
コード例(雰囲気つかみ用)
https://guide.elm-lang.jp/architecture/forms.html より抜粋
-- MODEL
type alias Model =
{ name : String
, password : String
, passwordAgain : String
}
-- UPDATE
type Msg
= Name String
| Password String
| PasswordAgain String
update : Msg -> Model -> Model
update msg model =
case msg of
Name name ->
{ model | name = name }
Password password ->
{ model | password = password }
PasswordAgain password ->
{ model | passwordAgain = password }
またね、 Elm
それで試しに小さなアプリを書いてみようとしたのですが、恥ずかしながら手も足も出ませんでした。
私が Elm 初日につまづいたところを JavaScript で素直に書くと次のようになります。
element.addEventListener('pointerdown', event => {
if (event.button !== 0) {
return
}
event.currentTarget.setPointerCapture(event.pointerId)
// event.clientX, event.clientY を使ってほげほげ....
})
elm-pointer-events パッケージ の README によれば、 pointer capture を使うには ポート を使う必要があるようです。 Elm からの要求を受け付けて setPointerCapture()
を行う「ポート」を JavaScript 側で用意 して、 Elm から呼び出す、という実装になります。
ポートはアプリ専用(パッケージはポート使用禁止)なので、アプリごとに setPointerCapture()
のポートを記述しなければなりません。
ニッチな API ならともかく PointerEvents でこの状況となると、普通にアプリを書こうとしたらポートだらけになるのでは… と想像して心が折れた私はいったん Elm と距離を置くことにしました(そもそも接近できてない)。
Elm のロードマップの Where is the localStorage package? というセクションには、 SPA 機能のあとには Web プラットフォーム のサポート拡大が最優先事項になる旨、さらには、 Web プラットフォームのサポート拡大のあとで Elm に戻ってくるのはアリだよ的なことまで書かれています。
そっか、じゃあ、またね、 Elm。
そんな折り、偶然見かけたのが Mint でした。
こんにちは、 Mint
ミントさんの代名詞 ナースとピコハン
Mint はシングルページアプリケーションを書くためのプログラミング言語を謳っています。私はアンチ SPA 派(ページごとに分けて実装する方が圧倒的にメンテナンスしやすいと信じているひと、 Paint Holding があれば尚更)なのでこの肩書きには魅力を感じないのですが、ドキュメントを眺めてみると Mint には注目する価値がありそうだと思いました。
特徴
- Elm っぽい型システム
- 宣言的に書けて型安全でリアクティブな
UI = f(State)
- ほぼ JSX だけど、 JSX と違って
if
式とかfor
式とか使えてめっちゃ便利
(ECMAScript の do expressions はまだ Stage 1 みたいだし)
- ほぼ JSX だけど、 JSX と違って
- 宣言的に書けて型安全でリアクティブな
Style = f(State)
- 宣言的に書けて型安全でリアクティブな Computed Properties
- Inlining JavaScript
- JavaScript の式をバッククォートで囲うだけ
- Elm との設計哲学の違いが端的に表れてるんじゃないかと思う
安全性を取るか、利便性を取るか
MIT アプローチか、 New Jersey アプローチか
- オールインワン
- 状態管理、 HTTP クライアント、 ルーティング、開発用サーバー、コードフォーマッター、テストランナー、などなどコミコミ
- Crystal で書かれている(めずらしい)
コンポーネントのコード例(雰囲気つかみ用)
- Realworld(https://github.com/mint-lang/mint-realworld)から拝借
component Article.Comments {
connect Stores.Comments exposing { status }
get content : Html {
if (Array.isEmpty(comments)) {
<div>
"This article does not have any comments yet."
</div>
} else {
<div>
for (comment of comments) {
<Article.Comment comment={comment}/>
}
</div>
}
} where {
comments =
case (status) {
Api.Status::Ok comments => comments
=> []
}
}
fun render : Html {
<Status
message="There was an error loading the comments."
loadingMessage="Loading comments..."
status={Api.toStatus(status)}>
<{ content }>
</Status>
}
}
Mint に触れてみた
以前からほしかった自分用の小さなアプリを Mint で書いてみています。
- arche: [WIP] non-designer’s icon designer
https://github.com/luncheon/arche
ほしかったのは、アイコンセットを補うためのアイコンデザインツールです。 Font Awesome や Material Design Icons を使っていて、ほしいアイコンがどうしても見つからないとき。自分で描けるものなら描きたいけど、高機能なデザインツールとか使いこなせないし、ベジェ曲線とか思うように描けないし… 直線と円弧だけのデザインツールがあったらどうだろう…? 的な感じで。
setPointerCapture()
は標準ライブラリに含まれていなかったものの、インライン JavaScript (バッククォートで囲まれた JavaScript の式)で普通に書けました。
fun onPointerDown (event : Html.Event) : Promise(Never, Void) {
if (event.button == 0) {
sequence {
`#{event.currentTarget}.setPointerCapture(#{event}.event.pointerId)`
/* event.clientX, event.clientY を使ってほげほげ.... */
}
} else {
Promise.never()
}
}
fun render : Html {
<svg onPointerDown={onPointerDown}>
/* ... */
</svg>
}
Mint に触れてみて
我々プログラマというものは、言語の好き嫌いについては一風変わった習性を持っています。 本屋で「プログラミング言語XYZ」といった本を見かけても、「わかってるよ、30秒もあれば、XYZで気に入らない所が何か見つかるさ」と反射的に思ってしまうのです。 プログラミング言語をマスターするまでには多大な時間と手間がかかり、その達成感も不確かな形で遅れてやってきます。 そのような努力をしない理由をさっさと見つけることが生存本能となっています。 つまり、そのような努力は賭け金の高い危険な投資であるので、否定的な決断を早目に下せば大いに安心できるというわけです。
The Case for D
http://dusers.dip.jp/modules/wiki/?Articles%2FThe%20Case%20for%20D%2F1
ということで、 Mint に 2 日間ほど触れてみて気になった点を挙げます。
- コンポーネントやレコード型などのスコープがファイルで区切られず、ファイルを越えて何でも見えてしまう
- 命名ポリシーでどうにかするしかない?
- Issue は挙がっていますが…
- Language is not package-friendly #208
https://github.com/mint-lang/mint/issues/208
- Language is not package-friendly #208
- 型推論がない
- たとえば
Maybe.map()
を使おうと思うと- こう書きたいのに
value |> Maybe.map(\x -> x + 1)
- 型推論がないので
value |> Maybe.map((x : Number) : Number { x + 1 })
- ECMAScript には Optional Chaining 版パイプライン演算子
?|>
or?>
の提案があったりする
Optional chaining support for the pipeline operator? · Issue #159 · tc39/proposal-pipeline-operator
https://github.com/tc39/proposal-pipeline-operator/issues/159value ?> x => x + 1
- こう書きたいのに
- 戻り値の型推論は(もうすぐ?)入りそう、引数の型推論は(まだ?)入らなそう
- 🚧 RFC: Code Visual Improvements #216
https://github.com/mint-lang/mint/pull/216
- 🚧 RFC: Code Visual Improvements #216
- たとえば
- コンポーネントのプロパティは必須にできず、デフォルト値が必須
- プロパティ渡し忘れバグの発見が遅れる
- 複雑なレコード型だとデフォルト値を書くのがつらい、かといって
Maybe
にしたくない - 現在審議(投票)中…
- Required properties #132
https://github.com/mint-lang/mint/issues/132
- Required properties #132
- Elm と同様、やはり DOM などの Web プラットフォーム API が弱い
- Elm と違って、 JavaScript の式がその場に書けるのでなんとでもなるっちゃなる、ただ型システムに守ってもらえなくなる
- README の Ways you can contribute に “create modules for not yet implemented Web APIs” って書かれてるし、これからって感じ
- TypeScript の lib.dom.d.ts をなんかいい感じにごにょごにょしたら使えたりしないものかね?(適当)
- Mint が知ってる CSS プロパティ 以外のプロパティを
style
ブロックに記述するとコンパイルエラーになるtouch-action
とかstroke-opacity
とか普通に書こうとして引っかかった- チェック自体はありがたいけどチェックを回避する手段もほしい
- インラインスタイル(仮想 DOM の
style
属性)は文字列で自由に書けるのでどうにかできるにはできるけど
- コンパイルエラーがコマンドライン上に表示されずブラウザー上に表示される
- VSCode 上でジャンプできないの地味に不便
- VSCode Extension がぜんぜん助けてくれない
まとめ
プログラミング言語 Mint を紹介しました。
特徴として挙げたメリットは期待通りでした。開発環境整備やライブラリ選定に悩むことはなく、書き味は良く、ビルドは爆速です。気になる点もたくさん書き連ねましたが、まだ成熟していないだけで、多くは時間が(実際には中の人の努力が)解決してくれそうな気がしています。型推論を入れてエディタープラグインをちゃんとするだけでもだいぶ使えるだろうと想像します。
いますぐ使うことをおすすめするつもりはありませんが、今度どこかで Mint の記事やニュースを見かけたときには興味を持って読んでもらえたらいいな、と思います。
null でした。
2020/04/07 追記
記事執筆時に利用したバージョンはそれぞれ
- Elm 0.19.1
- Mint 0.8.0
です。情報が古くなっている可能性がありますのでご注意ください。特に Mint は言語仕様もエコシステムも発展途上であり変化が速いです。 0.9.0 では型推論やインライン JavaScript の型指定、コンポーネントの必須プロパティなどが追加されています。
- Mint / Blog / 0.9.0
https://www.mint-lang.com/blog/mint-0.9.0
その他の記事
Other Articles
関連職種
Recruit