LoginSignup
8
8

More than 5 years have passed since last update.

Swiftの関数引数とタプルについて思ったこと

Posted at

Swiftの関数の引数は、常に一つ」を読んで,そうであるならば,


let g = {(a: Int, b: Int) -> Int in a + b}
var v: (Int, Int) = (1, 2)

var w = g(v)

とタプルを直接渡して関数起動してくれてもいいじゃないかと思います.
しかし「引数の数が合わない」というエラーであえなく撃沈.
引数リストを全部埋めるのが面倒くさいので前もって用意したタプルをどんと渡したいということも時にはあると思いますけど.例えば,4引数をとる関数fnがあったとして,

let x = (a+b, a-b, a*b, a/b) // 本当はもっと複雑な計算
let y = fn(x)       //どんと一発起動

なんてことをやりたいかも.
 

さて,件の記事からcall関数を再掲すると,

func call(f: A -> R, a: A) -> R {
return f(a)

となっています.タイプ指定を見るとクロージャfは,あくまで1つの引数を受け取って1つの結果を返す,と処理系に敢えて認識させてるからこの定義は通るんですね.どんなタイプであっても1つであれば受け付ける.
現処理系は,関数起動表現において,文法チェック後に,まず引数の数をチェックして,それから各引数のタイプチェックしている印象です.数と個々の要素のタイプチェックですね.関数名の後ろのカッコ表現をただのタプルと見なせば,これってただのタプルのタイプチェックですね.内部的には,確かに関数起動には"引数列というタプル"が唯一必要だということが分かります.

ところで,Swiftの言語リファレンス のParenthesized Expressionのところを見ると,

If there is only one value inside the parenthesized expression, the type of the parenthesized expression is the type of that value. For example, the type of the parenthesized expression (1) is Int, not (Int).

なんていう説明があります.(1)のタイプは(Int)じゃなくてIntであると.
であるならば,関数起動g(v)での(v)は実は((Int, Int))なのでタイプは(Int, Int)です.g(1, 2)と表現しているようなものです.全然問題ないじゃないですか.
単純にタプルとしてのタイプチェックだけをしてくれれば,g(a)も実行できるはず.

例えば,次のような変数a,bを定義したとき,

var a: (Int, Int) = (1, 2)
var b: ((Int, Int), Int) = ((1, 2), 3)

g(a)   // O.K
g(b)   // error

g(a)は(a)のタイプ合致で起動可能.
g(b)では(b)が(Int, Int)ではなくタイプ不一致だからエラーとなってほしいところです.そもそも引数の数なんてものはタイプに包含されているから,タイプチェックの前に数を勘定する必要なないはずです.
もう一度いいます,「引数の数はタイプに包含されている」んですよと.

8
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
8