特集:C#開発者のためのF#入門(後編) F#言語の基礎文法 bleis-tift2012/05/10 2012/05/11 更新 |
Page1
Page2
|
前回は、F#の概要や、関数型プログラミングの基礎、F#でよく使われるデータ構造のリストとタプルを説明した。今回後編では、F#でプログラムを書くに当たって必要最低限の文法を紹介していく。
■主要な文法
●if式
F#で条件による分岐を行うためには、if式を使用する。
|
|
F#のif式 |
字面上はほかの言語のif文と同じように見えるが、F#の「if」はほかの言語での条件演算子(例えばC#の「<条件> ? <trueの場合> : <falseの場合>」という式)に近い。F#の「if」は文ではなく式なので、値を持つ。そのため、「then」に続く式と「else」に続く式は同じ型を持つ必要がある。
以下のコードは、「then」に続く式の型と、「else」に続く式の型が異なるため、エラーとなる。
|
|
型が異なるためにエラーとなるif式 |
比較演算子は「==」ではなく「=」、「!=」ではなく「<>」を使用し、否定には「!」の代わりに「not」を使用する。次のコードは、比較演算子「=」を使った例だ。
|
|
比較演算子「=」を使ったif式のコード例 |
また、「else」は基本的に省略できない(省略できるケースについては後述)。
●letキーワード
letキーワードはすでに説明したが、もう少し詳しく見ていこう。
|
|
letキーワードを用いたコード例 |
関数「g」の中で関数「f」を呼び出しているが、この際、関数「f」は関数「g」よりも前に定義されている必要がある。つまり、関数「g」の後に関数「f」を書くとエラーとなる。これはC#やVB(Visual Basic)を使っている人がはまりやすいポイントなので、注意しておこう。
関数「fact」のように再帰関数を定義するためには、recキーワードを使って関数を定義する必要がある。この「rec」がないと、まだ定義していない関数「fact」を参照することになり、エラーとなる。以下のプログラムが何を表示するか考えてみてほしい。
|
|
このプログラムを実行すると、何が表示されるか? |
実際に実行して、自分の考えがあっていたかどうかを確認しておこう。
実行すると、5の階乗(5 * 4 * 3 * 2 * 1)である「120」ではなく、「20」が表示されたはずだ。これは、2番目の関数「fact」の定義の中で呼び出されている関数「fact」が、自分自身ではなく、以前に定義した関数「fact」(=引数をそのまま返す関数)だったからだ。
このように、F#では定義の順番は非常に重要な意味を持つ。
引数なしの関数も見ておこう。
例えば次のコードのように引数を付けないと、「hello」は関数にならない。
|
|
関数とはならないコード例 |
そのため、引数なしの関数は引数の位置に丸カッコの対(=「()」)を記述する。この「()」は、意味がないことを表す値であり、unitという型を持つ。unit型はC#でのvoid型に近いが、void型が値を持たないのに対して、unit型は「()」という値を持つという違いがある(unit型は値を持つため、実は引数がないわけではなく、「hello」は意味のない値「()」を受け取る関数である)。
また、戻り値がないメソッドでは、C#ではvoid型を戻り値の型として指定するが、F#ではvoid型の代わりにunit型の戻り値が返される。例えば、今まで使ってきたSystem.Console.WriteLineメソッドは、F#から使うとunit型の戻り値を返すように見える。
unit型は「()」という唯一の値を持つため、F#の関数は(例外で終了しない限り)戻り値を持つようになっている。意味はないが、以下のようなコードも記述できる。
|
|
C#から見ると戻り値のないメソッドだが、F#から見るとunit型の戻り値を返すメソッドとなっていることを確認するコード例 |
これにより、F#では戻り値のある関数もない関数も、統一的に扱うことが可能だ。
if式の説明で、「『else』は基本的に省略できない」と書いたが、「then」に続く式がunit型の場合のみ、「else」を省略することができる。次のコードはその例である。
|
|
if式で「else」を省略できる例 |
●レコード
F#でユーザー定義の型を作る場合、クラスではなく主にレコードと判別共用体を使用する。まずはレコードを見てみよう。
レコードは、
|
|
レコードの定義形式 |
という形式で定義する。
レコードはフィールドに名前の付いたタプルと考えることができる。
例えばタプルの説明で使った「名前と年齢」をレコードとして定義すると、以下のようになる。
|
|
「名前と年齢」をレコードとして定義するコード例 |
レコードに対する各種の処理を以下にまとめる。
|
|
レコードに対する各種の処理 |
今まで画面出力にはSystem.Console.WriteLineメソッドを使ってきた。しかし、レコードなどのユーザー定義型は、「%A」という書式指定を使うことで簡単に文字列化できるため、以降は(同様に画面出力できる)printfn関数を使用する。
さて、先ほどのコード例では、レコードのインスタンスの生成に型名が明記されていなかったが、例えばさらに以下のような型もあった場合はどうだろう(つまり、同じ型の組み合わせのレコードがある場合はどうなるのだろうか)。
|
|
先ほどのレコード「Person」と全く同じ型のフィールド群を持つレコードの定義 |
この場合、F#では「レコードのインスタンスを生成する直前で定義された型」のインスタンスが生成される。つまり、次のコード例のようになる。
|
|
全く同じ型のフィールド群を持つレコードがある場合のインスタンス生成の挙動 |
Dog型を定義した後でPerson型のインスタンスを生成したい場合は、次のように、フィールドに型名を修飾することで可能だ。
|
|
フィールドに型名を修飾することでレコードの型を明示する例 |
ジェネリック型のレコードを作りたい場合は、型変数(この例では「'a」や「'b」)を型名(この例では「Pair」)の後ろの山カッコ(< >)の中に記述する。
|
|
ジェネリック型のレコードの定義例 |
型変数名の先頭にシングルクォート(')が必要な点のみ注意してほしい。
続いて次のページでは、判別共用体を説明する。
INDEX | ||
特集:C#開発者のためのF#入門(前編) | ||
F#で初めての関数型プログラミング | ||
1.F#とは | ||
2.関数型プログラミングの基礎 | ||
3.リストとタプル | ||
特集:C#開発者のためのF#入門(後編) | ||
F#言語の基礎文法 | ||
1.主要な文法: if式/letキーワード/レコード | ||
2.主要な文法: 判別共用体/パターン・マッチ | ||
更新履歴 | |||||||||||||
|
- 第2回 簡潔なコーディングのために (2017/7/26)
ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている - 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう - 第1回 明瞭なコーディングのために (2017/7/19)
C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える - Presentation Translator (2017/7/18)
Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
|
|