step6 関数の定義
ここまでのステップで、数当てゲームの基本的なロジックは完成した。
しかし、現状のコードではProgram.fs のトップレベルにすべての処理が記述されており、再利用性や可読性が低い。
そこで、このステップでは F# における関数の定義方法を学び、判定ロジックを関数として切り出すことで、コードをよりモジュール化された、読みやすいものに改善する。
関数の定義方法
F#で関数を定義するには、let キーワードを使用する。
関数も変数と同様に let で束縛される値の一種であり、関数を定義することは、関数値を変数に束縛することに相当する。
基本的な構文は以下の通りだ。
let 関数名 パラメータ1 パラメータ2 ... = 関数本体例えば、2 つの整数の和を返す add 関数は以下のように定義できる。
let add x y = x + yこの例では、add という名前の関数を定義している。
add 関数は x と y という 2 つのパラメータを受け取り、x + y の結果を返す。
F#では、関数の戻り値の型は、型推論によって自動的に決定される。
もちろん、明示的に型を指定することも可能だ。
let add (x: int) (y: int): int = x + yTypeScript との比較
ここで、TypeScript で同様の add 関数を定義してみよう。
function add(x: number, y: number): number { return x + y;}//orconst add = (x: number, y: number): number => x + y;F# と TypeScript の関数定義にはいくつかの違いがある。
- F# では
functionキーワードではなく、letキーワードを使用する。 - F# では通常、型推論が使われるため、パラメータや戻り値の型を明示的に指定する必要がない (もちろん、指定することもできる)。
- F# では関数が値を返すため、明示的な
returnステートメントは不要 (末尾の式が関数の戻り値となる)。
どちらの言語も、関数を定義するための簡潔な構文を提供しているが、型推論や暗黙の戻り値など、F# にはより関数型プログラミングに適した特徴が見られる。
関数の使用
F#では、関数は値を返す。
関数を使用するには、単に関数名に続けて引数を記述する。TypeScript のように () で囲む必要はない。
let result = add 10 5printfn "%d" result // 出力: 15この例では、add 関数に 10 と 5 を引数として与え、結果を result 変数に代入している。
判定ロジックを関数に切り出す
それでは、Step 5 で作成した Program.fs の判定ロジックを関数として切り出してみよう。
まず、Result 型の定義はそのまま残す。
type GameResult = | TooBig | TooSmall | Correct次に、判定ロジックを judge という名前の関数として定義する。
judge 関数は、正解の数 answer とユーザーの入力 input を受け取り、Result 型の値を返す。
let judge answer input = match compare input answer with | 1 -> TooBig | -1 -> TooSmall | _ -> Correct関数を定義したら、型を見てみよう。
judge: int -> int -> Result と表示されるはずだ。
let judge: int -> int -> GameResult = match compare input answer with | 1 -> TooBig | -1 -> TooSmall | _ -> Correctこのように、-> を関数に適応すると、新しい関数に部分適応される。
たとえば、judge 42 は、int -> Result 型の関数になる。
これにより、関数の再利用性が高くなる。
Program.fs の全体像
ここまでの変更を適用した Program.fs の全体像は以下のようになる。
type GameResult = | TooBig | TooSmall | Correct
let judge answer input = match compare input answer with | 1 -> TooBig | -1 -> TooSmall | _ -> Correct
let answer = 42
printfn "正解は%dです" answerprintfn "1から100までの数字を入力してください。"
let inputNumber = stdin.ReadLine() |> intlet result = judge answer inputNumber
let message = match result with | TooBig -> "大きすぎます" | TooSmall -> "小さすぎます" | Correct -> "正解です"
printfn "%s" message書き換えたら dotnet run で実行してみよう。
実行結果はこれまでと同じになるはずだ。
まとめ
このステップでは、以下の内容を学んだ。
letキーワードを使った関数の定義方法- 型推論による関数の戻り値の型の決定
- 関数の呼び出し方法
- 判定ロジックの関数への切り出し
- 関数の部分適用
- F# と TypeScript における関数定義の比較
関数を適切に定義し、使用することで、コードの再利用性と可読性を向上させることができる。 また、F#では関数が第一級の値であり、変数に束縛したり、引数として渡したり、戻り値として返したりすることができる。
次のステップでは、ユーザーが繰り返し入力できるようにループを実装する。