komorebikoboshiのブログ

プログラミング記事(趣味レベル)が多め。

F#のfunction式への苦手意識が少しなくなったかもしれない

F#のmatch式、便利ですね!

let rec fib n =
    match n with
        | 0 -> 0
        | 1 -> 1
        | x -> fib (x - 1) + fib (x - 2)

こんな感じでパターンマッチが簡単に書けます。
さて、match式とよく似たものにfunction式というものがあります。

let rec fib =
    function
    | 0 -> 0
    | 1 -> 1
    | x -> fib (x - 1) + fib (x - 2)

実は私、このfunction式が苦手でして。なんかこう引数を明示しないのが気持ち悪いというか、うっかり

let rec fib n =
    function
    | 0 -> 0
    | 1 -> 1
    | x -> fib (x - 1) + fib (x - 2)

(* これは fib n x = ~ という2引数関数だと解釈される *)

とか書いてなんか引数の数がおかしくなったりとかします。
話変わって、Haskellとかもちょこちょこ触ってたりするのですが、Haskellだとこんな感じで関数が書けます。

fib 0 = 0
fib 1 = 1
fib x = fib (x - 1) + fib (x - 2)

引数が0の時は0、1の時は1、それ以外ならほにゃららといった感じですね。個人的には割とわかりやすく感じます。
で。F#のfunction式ですが、ちょこっと書き方を変更してみます。

let rec fib = function 0 -> 0
                     | 1 -> 1
                     | x -> fib (x - 1) + fib (x - 2)

なんとなくHaskellのと似ていません?F#では

let func1 = fun x -> x + 1

という風にfun式(いわゆる無名関数)をつかっても関数を定義できますが、上のコードはfun式による「引数が0の時は0、1の時は1、それ以外ならほにゃらら」に対応したものと言えるでしょう。

(* 実際にこのようなコードを書けるわけではない *)
let rec fib =
    fun 0 -> 0
    fun 1 -> 1
    fun x -> fib (x - 1) + fib (x - 2)

実は、F#のfunction式はmatch式と同じではなくて、むしろfun式のお友達です。よって

let rec fib n =
    match n with
        | 0 -> 0
        | 1 -> 1
        | x -> fib (x - 1) + fib (x - 2)

let rec fib = function 0 -> 0
                     | 1 -> 1
                     | x -> fib (x - 1) + fib (x - 2)

は微妙に意味が違っていて、前者は「fibという関数を関数定義文で定義する」であり、後者は「関数式を評価して得た関数値をfibという名前に束縛している」となります。
function式はfun式の仲間なのでこのように

[1 .. 20]
|> List.map (function
             | x when x % 15 = 0 -> "FizzBuzz"
             | x when x % 5 = 0 -> "Buzz"
             | x when x % 3 = 0 -> "Fizz"
             | x -> string x)

高階関数の引数に直接書くこともできます。
そんなわけで、functionはfunの代わりだと思えば少しは苦手意識も減るかなあ、と。