Validated applicative functorの良さ + Traverse

関数型プログラミングの知られざる(?)役者、Validatedについて語る面々(Traverseもちょっとあるよ)
2

前提: 型クラス

型クラスの話をしています。型クラスは、ダックタイピングのすごく良いやつです(適当)(コメントで識者がツッコんでくれる)

型クラス(とその具体例であるインスタンス)にはいろいろあるけど、今回はValidatedTraverseについて話しているよ

  • 言語によって呼び名はいろいろあるけどここではScala(のCatsライブラリ)での呼び名で書いています
  • ValidatedはApplicative、Functorのインスタンスだよ(ApplicativeとFunctorのインスタンスであることを強調してValidated applicative functorと呼ぶことがあるよ)
    • Monadじゃないよ
    • Monad版はEitherが相当するよ
  • TraverseはFunctorにtraverseという操作を導入した型クラスだよ
    • 例えばListはTraverseのインスタンスだよ

Validated

Validatedは成功した計算をまとめるか、エラーを累積してまとめるかの操作を行うことができるデータ型だよ

https://typelevel.org/cats/datatypes/validated.html

https://qiita.com/nozomitaguchi/items/66bbee966e59281a68e8

類似の概念にEitherがあるよ

Eitherはエラーが発生した時点で計算を打ち切ってすぐに返るけどValidatedは全てのエラーを集めて回ってくれるよ

パサカタ @hisaketM

一番身近でかつ知ってたら「これ無しにコード書くとか機械語でコード書くようなもんだろ」ってなるのに全然知られてない構造、たぶんValidated applicative functorが1位な気がする(知ってれば、バリデーションがしたくなったらまずこれなしには話が始まらないのに…となる)

2023-04-28 10:19:47
はけた@できるExcel2021 @excelspeedup

Validation型を教えてもらったときに、感動した覚えがあります。 twitter.com/hisaketM/statu…

2023-04-28 17:32:53
がくぞ @gakuzzzz

少なくとも自分が係わった殆どのプロジェクトでValidationエラーを可能な限り集約して返す要件は存在していて、Validatedみたいなデータ構造は本当に必須と感じている

2023-04-28 18:25:42
jskmt @jsoizo

ValidatedとNonEmptyListの合わせ技は必須だなぁと感じること多い。 kotlinというかarrowだとValidatedとEitherとの差がほぼなくてdeprecatedになっちゃったけど。 twitter.com/gakuzzzz/statu…

2023-04-28 20:27:08

Applicative

ValidatedはApplicativeのインスタンスだよ

Applicativeは関数を適用すること、または2つの値の合成を一般化して、さらに拡張した振舞い(例: 関数と引数の両方が失敗するおそれがある)を導入できるようにした仕組みだよ

ApplivativeはFunctorに2つの操作、apとpureを導入した型クラスだけど、apをmap2で代用することもできるよ(相互に定義可能)

https://typelevel.org/cats/typeclasses/applicative.html

ちなみに、Functorは変換を一般化して、さらに拡張した振舞い(例: リストの全ての要素を変換する)を導入できるようにした仕組みだよ

おまけ: Monad逐次処理 を一般化して、さらに拡張した振舞い(例: 逐次処理が非同期処理で行われる)を導入できるようにした仕組みだよ

Kory @Kory__3

@yaito3014 applicative は map2<A,B,C>(fa: F<A>, fb: F<B>)(abToc: (A, B) -> C): F<C> ができるやつで、 例えば 「標準的な」Result モナドに関しては match fa { case Err(e) -> Err(e), case Ok(a) -> match fb { case Err(e) -> Err(e) case Ok(b) -> Ok(f(a,b)) } } ができます

2023-04-28 18:16:04

注: ResultモナドというのはRustの文脈

Kory @Kory__3

モナドの有用な例は?と言われて出てくる第一候補が LL(k) パーサモナドだし、じゃあ Applicative は?って言われると Validated みたいなとこある

2023-04-28 17:37:18
Kory @Kory__3

Twitter定期的に validated applicative の話になるなって思って validated applicative lang:ja で検索したら僕とがくぞさんと hisaketM さんしか検索結果に出てこないんだけど検索バグッてる?

2023-04-28 19:54:38
Kory @Kory__3

@windymelt Applicative として使うのではなく Validated のメソッドを直接使ってたみたいなパターンですか?

2023-04-28 20:06:28
Windymelt(めるくん)🚀❤️‍🔥さんと他1000人 @windymelt

@Kory__3 あ、ValidatedがApplicativeであるということを意識してなかったです。より強いMonadだという認識が強かった

2023-04-28 20:25:57
Windymelt(めるくん)🚀❤️‍🔥さんと他1000人 @windymelt

CatsとかだとPointedは省略されてApplicativeに包含されてるから忘れがち(ScalazだとPointedとApとでApplicativeになってた気がする)

2023-04-28 18:20:31

ライブラリにもよるけど、Applicativeを直接Functorから派生させる流派とPointed(pureを導入する)を挟む流派があるよ(Catsは前者、Scalazは後者)

使うときはあまり考えなくていいよ

Windymelt(めるくん)🚀❤️‍🔥さんと他1000人 @windymelt

Applicative、map2から定義する方法とapで定義する方法がある?(よくわかってない)(pureはオマケだと思う)

2023-04-28 18:17:11
Windymelt(めるくん)🚀❤️‍🔥さんと他1000人 @windymelt

たぶんmap2もapもどっちかが定まれば互いに定義できる?と思うんだけど

2023-04-28 18:17:44
Kory @Kory__3

@windymelt def ap[A,B](fab: F[A => B], fa: F[A]) = map2(fab, fa, (fn, a) => fn(a)) def map2[A,B,C](fa: F[A], fb: F[B])(f: (A, B) => C): F[C] = ap(fa.map(a => b => f(a,b)), fb)

2023-04-28 18:32:02
Windymelt(めるくん)🚀❤️‍🔥さんと他1000人 @windymelt

@Kory__3 うお〜ありがとうございます。実際どうなのか分からないのですがなんかcurryingみたいな趣がありますね。

2023-04-28 18:39:33

Traverse

TraverseはFunctorにtraverseという操作を導入したもので、FunctorとApplicativeの合わせ技的な便利な操作ができるよ

(ScalaMatsuri 2023で見たツイートを末尾に置きました)

Kory @Kory__3

traverse も「これ見えてなかった時ループを全部 GOTO で書いてたようなもんよな」という気持ちになる

2023-04-28 17:22:09
がくぞ @gakuzzzz

次の僕のセッションのスライドはこちらです。「traverse を制する者はコードを制す」gakuzzzz.github.io/slides/control… お手元で見たい場合など #scalamatsuri

2023-04-15 13:58:56