SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

japan.internet.com翻訳記事

F#で学ぶ関数型プログラミング入門

関数型プログラミングの主な概念とF#での利用例

型とパターンマッチングを改善する

 型引数(type augmentations)を使うと、型の周辺で提供される機能を効率よく扱えます(リスト1を参照)。

リスト1. 単純な型を使って処理速度を向上する
#light

// 図形は、四角形、円形、または正方形です。
// 正方形は特殊な四角形です。
type Shape =
    | Rectangle of int * int * int * int
    | Circle    of int * int * int
with
    static member Square(x, y, size) = Rectangle (x, y, x+size, y+size)

    member self.Perimeter =
        match self with
        | Rectangle (x1, y1, x2, y2) ->
            Float.of_int (2*(x2-x1)+2*(y2-y1))
        | Circle (x, y, r) ->
            Float.of_int (2*r) * System.Math.PI
end

// 絵は図形の集まりです。
type Drawing = Drawing of Shape seq
with
    member self.TotalInkNeeded =
        match self with
        | Drawing shapes ->

            shapes |> Seq.sumByFloat (fun s -> s.Perimeter)
end

 通常、型定義は、その型に属する値を操作する基本的な抽象制御メカニズムと手を組みます。パターンマッチング(特定の形状のツリーや特定のサイズおよび内容のリストのような、値の構造へのマッチング)、匿名関数(ラムダ式とも呼ばれる、必要な時点で作成される名前のない関数)、集計高階関数(列挙可能なデータに適用する関数)は、このようなメカニズムです。例えば、リスト1のSeq.sumByFloatは、Seq型(すべての列挙可能な型を表す型であり、seqはこの型の標準的な省略形としてDrawingでも使用)に対する静的な集計関数であり、図形の外周を計算する匿名関数を受け取って、これを絵に含まれるすべての図形に適用し、その結果を集計して絵を描画するために必要なインクの量を求めます。

パイプと共通集計関数について

 TotalInkNeededの定義になぜパイプ( |>)演算子が使われるのか不思議かもしれません。この演算子は、F#標準ライブラリに次のように定義されています。

let (|>) x f = f x

 パイプは中置演算子ですから、左側のオペランドを右側のオペランドに送信(パイプ)するという形で関数呼び出しを上品に表現できます。この記法には、2つの利点があります。1つは引数をかっこで囲む必要がないことで、もう1つはコンパイラの型推論を支援できることです(これは、型がわかっている値を左側から渡すことにより、型情報が供給されるからです)。

 sumByFloatは、折りたたみ(folding)の特殊なケースです。これは比較的一般的な関数型パターンであり、1つの関数と1つの初期アキュムレータを受け取ってから、その関数を初期アキュムレータを使ってコレクションの最初の要素に適用し、さらにその結果を2番目の要素に適用する、といった操作をコレクションの最後の要素にまで繰り返してアキュムレータの最終的な値を取得します。F#標準ライブラリでは、折りたたみ、マッピング(関数をコレクションのすべての要素に適用し、その結果の値を要素として持つ新しいコレクションを構築する)、反復(すべての要素に対して同じ操作を繰り返す)がすべてのジェネリックな列挙型でサポートされます。これらの集計操作と、そこから派生するより特殊な操作の多くは、関数型プログラマのツールセットで最も頻繁に利用されるツールです。

 最後に、ここで作成した新しい型を対話式セッションで簡単にテストしてみましょう(リスト1のコードを使用)。例えば、次のコードは(シーケンスの内包を使用し、結果をDrawingコンストラクタにパイプすることで)20個の新しい図形を作成してから、これらの図形を描画するために必要なインクの量を計算します。

> let a = seq { for i in 1 .. 20
                 -> if i % 3 = 0 then
Circle (20, 20, i)
                     elif i % 3 = 1 then
Rectangle (20, 20, 20+i*2, 20+i)
                     else
Shape.Square (20, 20, i) } |> Drawing;;

val a : Drawing

> a.TotalInkNeeded;;
val it : float = 1123.840674

まとめ

 この記事では、関数型プログラミングの主な概念と、これらの概念をF#でとりあえず使ってみる方法を解説しました。その過程で、基本型の定義、単純な型、関数、構造化された値、無限遅延シーケンス、集計高階関数を使う引数化されたメンバを持つ型、ラムダ式、パイプ演算子について学習しました。また、図形を表す値の列挙をシーケンスの内包を使って作成しました。この連載の次回の記事では、これらの機能をさらに詳しく学ぶと共に、F#の生産性カーブを確実に上昇させる高度な関数型構造について学習します。

この記事は参考になりましたか?

連載通知を行うには会員登録(無料)が必要です。
既に会員の方はを行ってください。
japan.internet.com翻訳記事連載記事一覧

もっと読む

この記事の著者

japan.internet.com(ジャパンインターネットコム)

japan.internet.com は、1999年9月にオープンした、日本初のネットビジネス専門ニュースサイト。月間2億以上のページビューを誇る米国 Jupitermedia Corporation (Nasdaq: JUPM) のニュースサイト internet.comEarthWeb.com からの最新記事を日本語に翻訳して掲載するとともに、日本独自のネットビジネス関連記事やレポートを配信。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

Adam Granicz(Adam Granicz)

F#の開発、トレーニング、コンサルティングのトップ企業IntelliFactory社のCEO。F#に関する最も包括的なガイドである『Expert F#』をF#言語デザイナのDon Symeと共同で執筆。関数型プログラミング言語を研究し、カリフォルニア工科大学(California Institute of Technology)の修士課程を修める。メールでの連絡先はgranicz.adam@intellifactory.com

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/3041 2008/10/10 14:00

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー