komorebikoboshiのブログ

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

数学の「群」がインターフェースに見えた

前に数学ガールを読んでいるってことを書いたけど、その中で群というものが出てくる。

群の定義(群の公理)
以下の公理を満たす集合を群という。


G1 演算*に関して閉じている。
G2 任意の元に対して、結合法則が成り立つ。
G3 単位元が存在する。
G4 任意の元に対して、その元に対する逆元が存在する。

以上が群の定義で、この条件を満たすものは全て群として扱える。
これは、すごいことだと思う。この条件さえ満たしていれば、それ以外にどんな性質を持っていたとしても群のさまざまな定理に従うのだから。
そしてこれは、プログラミングにおけるインターフェースに似てるなあ、と。(型クラス、っていう方がいいのかなぁ?よく分からない)そのクラスがどんな振る舞いをしようとも、IComparableさえ有ればソートしてやんよ、みたいな。わずか1つのメソッドを実装するだけで、どこかの誰かが作った超高性能なソート関数を自分のクラスでも利用することができる。これも、すごいことだと思う。
群の定義はたった4項しかない。このわずかな道具だけを使って理論を組み立てていく。それは大きな制約かもしれないけど、反面、条件が少ないからこそより多くの対象を扱えるのだと思う。プログラミングのインターフェースも、大抵1つか2つのメソッドを実装するだけで便利機能が扱える。(CurrentとMoveNextを実装するだけでLINQが使い放題に!)*1少ない条件でどうにかしてくれているおかげで使う方は楽をできる。
ちょっと記事のタイトルから話がずれたけど、抽象化された概念を使って物事を組み立てることで、より応用範囲の広い理論やプログラムが作れるんだなあ、とまとめっぽい事を書いておく。テトラちゃんかわいい。*2

*1:yieldを使えばもっと楽チンに

*2:肝心の数学的な内容は全然頭に入ってない。次は数式をじっくり追いながら読もう

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の代わりだと思えば少しは苦手意識も減るかなあ、と。

アクア、はじめました。

というわけでAQUA(リンク先18禁)をプレイ中。またのんびりやっていくつもり。さすがに最後にどばっと感想を書くのは疲れたので、途中途中で適当に書いていこうかな。