読者です 読者をやめる 読者になる 読者になる
ようこそ。睡眠不足なプログラマのチラ裏です。

F#では、パターンマッチを「match x with」と書く流派と「x |> function」と書く流派がございます。

プログラミング F#2.0 F# パターンマッチ イディオム

とあるF#er達のつぶやき


ながと(@nagat01)さんというか、ながと2(@nagat02)さんが、私のツイートに反応してくれていました。うれしいな。
「いにしえからの言い伝えによると」というしょうもない冗談というか、余計意外の何ものでもない表現を付け加えてしまったためか、
私の言いたかったことは伝わっていないようです。なので、たいした話ではないのですがちょっと書いてみます。ながとさんのアイコンがかわいいです。



「x |> function」という書き方だと、インデントを浅く保てる!

さて、まずコンピューテーション式を用いて、最近マイブームのMaybeモナドを用意してみました。
もちろんモナド則を満たしています。だらだら説明する元気もないので、百聞は一見になんとやらに則って、
詳細についてはコードおよびコメントを参照してください。(モナドうんぬんはわからなくても問題ありません)

open System
let bind x k =
    match x with
    | Some value -> k value
    | None   -> None

let mreturn x = Some x

/// Maybeモナド
type MaybeBuilder() =
  member this.Bind(x, k) = bind x k
  member this.Return(x)  = mreturn x
  member this.ReturnFrom(x) = x
  member this.Delay(f)   = f()
  member this.Combine(a, b) = if Option.isSome a then a else b ()
  member this.Zero() = None
  member this.For(inp,f) =
      seq {for a in inp -> f a}
  member this.Yield(x) = mreturn x
  member this.YieldFrom(x) = x

let maybe = new MaybeBuilder()

(*
let x = 1
let m = maybe { return 3 }
let f x = maybe { return 4 + x }
let g x = maybe { return 2 * x }
let (>>=) m f = maybe {let! x = m
                       return! f x}

let return' x = maybe { return x }

let prove (left,right) = 
  maybe {let! x = left
         let! y = right
         return x = y}

prove (return' x >>= f, f x) |> Option.get |> fun b -> printfn "モナド則1 : %b" b |> ignore // true
prove (m >>= return', m) |> Option.get |>fun b -> printfn "モナド則2 : %b" b |> ignore // true
prove ((m >>= f) >>= g, m >>= (fun x -> f x >>= g)) |> Option.get |> fun b -> printfn "モナド則3 : %b" b |> ignore // true
Console.ReadLine () |> ignore
*)

type QB = System.Linq.IQueryable 
let charlotte () = invalidArg "mo:Magica option" "マミられました"

type Magica =
  |Madoka of QB
  |Sayaka of QB
  |Mami of QB
  |HomuHomu of QB
  |Kyouko of QB

(* 一般的な書き方(1)
   "match x with"と書く流派の典型 
   改行してから"match x with"でパターンマッチします *)
let keiyaku0 mo = 
  maybe { let! x = mo
          return
            match x with
            |Madoka   m -> m.Expression 
            |Sayaka   m -> m.Expression
            |Mami     m -> charlotte ()
            |HomuHomu m -> m.Expression 
            |Kyouko   m -> m.Expression } 

(* return と同じ行に"match x with"を書きます。できればこう書いてしまいたいんだけど、
   インデントがおかしいよ!と怒られてしまいます。*)
let keiyaku1 mo = 
  maybe { let! x = mo
          return match x with
          |Madoka   m -> m.Expression 
          |Sayaka   m -> m.Expression
          |Mami     m -> charlotte ()
          |HomuHomu m -> m.Expression 
          |Kyouko   m -> m.Expression } 

(* 一般的な書き方(2)
   "match x with"と書く流派の別解
   return と同じ行に"match x with"を書きます。でも、インデントが深くなってしまうま *)
let keiyaku2 mo = 
  maybe { let! x = mo
          return match x with
                 |Madoka   m -> m.Expression 
                 |Sayaka   m -> m.Expression
                 |Mami     m -> charlotte ()
                 |HomuHomu m -> m.Expression 
                 |Kyouko   m -> m.Expression } 

(* "x |> function" と書く流派なら、すっきり!
   もちろん、この書き方しかしないというわけではないけど、
   インデントを浅く保つことができるので、わたしはこの書き方が好きです
   モテるF#女子はこう書きます>< *)
let keiyaku3 mo = 
  maybe { let! x = mo
          return x |> function
          |Madoka   m -> m.Expression 
          |Sayaka   m -> m.Expression
          |Mami     m -> charlotte ()
          |HomuHomu m -> m.Expression 
          |Kyouko   m -> m.Expression } 


「x |> function」の方をより好むと言っているだけで、
「match x with」とは書かないと言っているわけではありませんので、くれぐれも誤解のないように。