だとしたら、Swiftではカリー化は不要ということになってしまう。
すなわち、ざっくり言うとカリー化とは複数の引数を1つに減らすことを指します - Swiftで関数のカリー化(currying)入門
Swiftの関数は、つねに一つの値を受け取り、一つの値を返すのだから。
以下のコードを動かしてみれば、それがわかる。
func call<A,R>(f:A->R, a:A)->R {
return f(a)
}
func id(i:Int)->Int {
return i
}
func add(x:Int, y:Int)->Int {
return x + y
}
call(id, 42) // 42
call(add, (21,21)) // 42
上記のcall()
は、「『型Aの値を一つだけ取って型Rの値を返す関数』と『型Aの値』を取って『型Rの値』を返す関数」なはずなのに、「Int
とInt
を取ってInt
を返す」関数も受け取っている。
なぜか?
「Int
とInt
を取ってInt
を返す」関数なんて、はじめからどこにもなかったからだ。
あったのは、
「(Int, Int)
を受け取ってInt
を返す関数」
だったのだ。
全てのSwiftの関数は、tupleを一つだけ受け取る関数なのである。
Haskellの言葉で言えば、上記のadd()
は
add:: Integer -> Integer -> Integer
ではなく
add:: (Integer, Integer) -> Integer
ということになる。
add()
の本当の姿は、
func add(arg:(Int,Int))->Int {
let (x, y) = arg
return x + y
}
だったわけだ。
ちなみに(Int, Int)
は、Int
とは独立した固有の型である。そしてInt
は(Int)
でもある。ので要素数ゼロのtupleである()
を除く全ての値は、必ず.0
というプロパティが存在する。
let n = 0
n // 0
n.0 // 0
n.0.0 // 0
n.0.0.0 // 0
// ちなみに0.0.0... は syntax error
// さもないと 0.0がDouble(0.0)なのか(0).0なのか判別不能になる
さらに
func hello(){ println("hi") }
は、()
を受け取って()
を返す関数であり、
call(hello, ())
は期待通り動く。
The Swift Programming Languageには
Tuples are particularly useful as the return values of functions
なんてのんきに書いてあるが、便利どころかSwiftでは全ての値がtupleなのだ。通常の値は要素数1のtupleで、「値がない値」すら、要素数0のtuple。
このことを知らなくても、普通の関数やclassやstructやenumは書けるのけど、上記のようにジェネリクスを使う場合、このことは必須の知識となる。
大事なことなのにアマツバメ本にきちんと明記していないので、記事にした次第。
(Dan, Swift, Newbie)