Swiftの関数の引数は、常に一つ

  • 238
    Like
  • 0
    Comment
More than 1 year has passed since last update.

だとしたら、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の値』を返す関数」なはずなのに、「IntIntを取ってIntを返す」関数も受け取っている。

なぜか?

IntIntを取って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)