ListやらSeqとかのパフォーマンス測定の時にコメント頂いた内容で
なぜ関数に()
を付けないといけなかったか?がずっと不思議だった。
「F#の関数定義では()はつけなくていいハズなのに、なぜ明示的につけるのか?」という勘違いが、いらぬ混乱を招いていた。
C言語ファミリーの関数定義で必要なvoid main(){...}
の()
とは意味合いが違う。
2020/2/26 誤りがある事をご指摘いただいたため、内容を訂正しました!
まとめ
わかりにくいのでunitを()、構文としての()をカッコと表現してます。
- letは値を束縛するための機能である
- F#では全ての関数が値とみなされる。関数値とも呼ぶ
- ()はunit型の定数パターンである
- 引数がないものは関数ではない
- 引数があるものは関数である
- 型注釈に使うカッコは関数定義の構文の一部ではない
- 関数の定義とカッコには直接の関係はない(優先順位を持たせるために使う)
- タプルを使うとカリー化は無効になる
letって何
名前と定義(値または関数)を関連付ける。
let t = 103 // 値を束縛
let s = "JNR" // 値を束縛
let add1 x = x + 1 // 1つの引数を持つ関数を束縛
let add x y = x + y // 2つの引数を持つ関数を束縛
パターンって何
letやラムダ式や関数の引数(パラメータ)を処理するときに使われる。
let t = 103 // 定数パターン
let n = () // 定数パターン
let add1int (x:int) = x + 1 // 引数に型の注釈がつけられたパターン
let add1int (x:int) :int = x + 1 // 戻り値の型を明示
検証用コード
// unitの値(副作用あり)
let a = printfn "a" // unit
// unitの値(副作用なし)
let b = () // unit
// unit引数を受け取りunitを返す関数
let c () = printfn "b" // unit -> unit
// 引数xを受け取りunitを返す関数
let d x = printfn "%A" x // 'a -> unit
// dを冗長に書いた場合
let e = fun x -> printfn "%A" x // 'a -> unit
// 引数xに無駄にカッコをつけているだけ
let f (x) = printfn "(%A)" x // 'a -> unit
// gは引数xとyを受け取りunitを返す関数
let g x y = printfn "%A%A" x y // 'a -> 'b -> unit
// gを冗長に書いた場合
let h = fun x -> fun y -> printfn "%A%A" x y // 'a -> 'b -> unit
// 引数として、xとyのタプルを1つ受け取りunitを返す関数
let i (x, y) = printfn "(%A,%A)" x y // 'a * 'b -> unit
// intの値(副作用なし)
let j = 2 // int
// 2を返す関数
let k = fun _ -> 2 // 'a -> int
let l = fun () -> 2 // 'a -> int