ようこそ。睡眠不足なプログラマのチラ裏です。

ScalazのValidationもFSharpxのValidationもApplicative



ドラゴンズドグマが楽しみだったり、しおりを温めていたScala実践プログラミングの読書を再開したりな今日この頃。
ご多聞に漏れずわたくしも五月病なので軽めのネタで。とゆーかですね、FSharpxのステマです。



FSharpxのValidationでFizzBuzz

元ネタ

ScalazのValidationでFizzBuzz
http://d.hatena.ne.jp/terazzo/20111015/1318692810


続・ScalazのValidationでFizzBuzz
http://d.hatena.ne.jp/terazzo/20111018/1318959813



そもそものきっかけはこのあたり


ScalazのValidationの謎
http://d.hatena.ne.jp/terazzo/20111022/1319295098




勉強になります。ということで、「ScalazのValidationはモナドではない」であっていました。しかしながら、Scalazの場合は「動作を変えてモナドインスタンスにすることもできる」んですね。でもそれってどうなの?エラー情報をaccumulateしないValidationって一体何。とっても意味ないんじゃー感がするんですが。できるというだけでやらないですね。



で、FSharpxというF#のOSSライブラリでも同じくValidationが実装されていまして、エラーをListMonoidとして扱ってエラー情報をaccumulateします。もちろんFSharpxのValidationもモナドではなくアプリカティブ(Applicative)として実装されています。ちょっと関連する以下のようなつぶやきも踏まえつつ、FSharpxと友達になるべくこれでFizzBuzzしてみましょう。




FSharpxの中の人的には、Choice<'T1,'T2>が生で使われちゃうこともある程度許容しているような雰囲気もなくはないですが、
生でヤっちゃうといろいろとアレということで、判別供用体のChoice1Of2とChoice2Of2を申し訳程度にラップしておく。

let success = Choice1Of2
let failure = Choice2Of2

open FSharpx.Validation

let createChoice d s = fun n -> 
  if n % d = 0 |> not then 
    success n
  else 
    failure [s]

let fizz = createChoice 3 "Fizz"
let buzz = createChoice 5 "Buzz"
let (<*) a b = lift2 (fun x _ -> x) a b
let fizzbuzz n = 
  fizz n <* buzz n
  |> function 
  | Success n -> string n
  | Failure e -> List.fold (fun a b -> b + a) "" e

[1..100] |> Seq.iter (fun x -> fizzbuzz x |> printfn "%s")

System.Console.ReadLine () |> ignore

って、ちょっと待って。FSharpxにおいてもValidationはちゃーんとApplicative考慮されていますし、当然のようにプログラムをApplicativeスタイルで書くための(<*)演算子はValidationモジュールにすでに定義済みです。上でわざわざ書いたのは、lift2していますよということを強調したかっただけでした。あとついでといっちゃーなんですが、お気に入りの「にっこり演算子」もおまけで追加しておきましょう。

let success = Choice1Of2
let failure = Choice2Of2
let (^-^) x f = x f (* にっこり *)

open FSharpx.Validation

let createChoice d s = fun n -> 
  if n % d = 0 |> not then 
    success n
  else 
    failure [s]

let fizz = createChoice 3 "Fizz"
let buzz = createChoice 5 "Buzz"
let fizzbuzz n = 
  fizz n <* buzz n
  |> function 
  | Success n -> string n
  | Failure e -> List.fold (fun a b -> b + a) "" e

[1..100] |> Seq.iter ^-^ fun x -> fizzbuzz x |> printfn "%s"

System.Console.ReadLine () |> ignore


シンプル。Validation本来の使い方とはちとズレていますが、サンプルとしてはイメージがつかみやすく結構わかり良いんじゃないでしょうか。元ネタのterazzoさんナイスですね。


参考
Scala の Either についての考察
http://d.hatena.ne.jp/xuwei/20110927/1317156625

Scalaz 6.0.4 と Haskell (GHC7.4.1) を比べてみることによってScalazのclassを分類して理解してみる
http://d.hatena.ne.jp/xuwei/20120204/1328377968


twitterで回答してくださった@xuwei_kさんの記事、参考になりました。