haskell-jp / random #107 at 2025-05-08 17:13:28 +0900

新たな構文を思い付きました。

data Foo = Foo {
  bar :: IORef Int
, baz :: TVar Int
}

みたいなデータ型があるとき、applicative style を使うと

Foo <$> newIORef 0 <*> newTVarIO 0

のように初期化できます。

しかし、フィールド名が使えないので、フィールド名による検索とか、フィールドが増減したときの編集とかがイマイチです。以下のような構文があると便利だと思うのですが、どう思いますか?

Foo {
  bar <- newIORef 0
, baz <- newTVarIO 0
}
アプリカティブなので、一部のモナドだと並列実行しますが、 do に酷似しているので順番がありそうに見えてしまうのが気になります
まあ、慣れかもしれませんが…
あー、そうですね。
ダメかなぁ?
あと、こんなことを書いて、なんで実行できないのか困惑する人が出て来るかも?

Foo {
  bar <- newIORef 0
, baz <- if isBarHoge bar then error "hoge" else newTVarIO 0
}

私もアプリカティブスタイルで書きたいけどレコードのフィールド多いとよく分からなくなってしまう問題は気になるんですよね。
特にcreatedAtとupdatetAtを同一のgetCurrentTimeで初期化したい時とか。
Hiromi ISHII / mr_konn
ApplicativeDoRecordWildCards を組み合わせれば既に似たようなコードを書けると思います。そして、Applicative の場合も実行順は本質的に重要になってくるので、そこは構文上回避できないですね
Hiromi ISHII / mr_konn
前職や趣味コードだとこんな感じに書いていますね。IO モナドなのでこれだと恩恵があまり見えないかもしれませんが、束縛変数の間に依存関係がないので、これは ApplicativeDo 言語拡張が有効化されていれば

foo = Foo <$> newIORef 0 <*> newTVarIO 0

に脱糖されます。
おー。
そんなことができるんですか!
ありがとうございます。
Hiromi ISHII / mr_konn
Applicative はだいたい「変数の間に依存関係がない限定的な do 記法が使えるファンクタ」だと思ってよい、という気持ちを明確化しているのが ApplicativeDo 言語拡張ですね(このあたり関数型まつりで話すつもりです
Hiromi ISHII / mr_konn
現状最後の stmt が pure や return の呼出(や $ による亜種)でないといけないという制限があったりします(理論的というよりは実装上面倒くさいので妥協してそうなっているはず)。詳細は以下にあります
https://ghc.gitlab.haskell.org/ghc/doc/users_guide/exts/applicative_do.html
このスタイルをあちこちで使ってみました。
大変素晴らしいです。
ありがとうございました!
ApplicativeDo + RecordWildCards は optparse-applicative でよく使いたくなる書き方で、READMEにも書かれています。
https://hackage.haskell.org/package/optparse-applicative