Avatar
omochimetaru 1/27/2020 7:37 AM
あーーなんか閃いてきた
7:38 AM
(移動中・・・
7:43 AM
sequences.map { $0.first }
7:43 AM
↑ここのmapに与えてる関数の型を考えたんですけど
7:43 AM
<T: Collection>(_ x: T) -> T.Element (edited)
7:44 AM
↑型としてはこのように書けると思います。
7:44 AM
で、何が引っかかっていたかと言うと
7:44 AM
今のSwiftでは関数型オブジェクト(クロージャ)は、 ジェネリックパラメータを取れないんです
7:44 AM
だから、まずそこを拡張する必要がある。
7:45 AM
次に
7:46 AM
ある多相な型関数 <A>(A) -> B を考えると
7:47 AM
あいや、 <A>(A) -> <B>B かもしれないんですけど
7:47 AM
この計算(AからBを求めること)を記述できる言語機能は
7:47 AM
多分 struct に対するメンバの typealias しかない。
7:47 AM
で、ただ、 <A>A が多相なので
7:48 AM
<A> に与えられる実際の型を規定するのが、
7:48 AM
言語機能としての protocol だと思う。
7:49 AM
つまり、 <A>(A) -> <B>Bprotocol AP { associatedtype R } なときに、 <A: AP>(A) -> R な式が持ってる型。
7:51 AM
普通のクロージャ構文だと、 $0 って書いた時点でもうなんらかの T としてのコンパイルになっちゃってクロージャも (T) -> U になるけど、 そうじゃなくて <A: P>(A) -> U のほうにならないといけない。
7:51 AM
でそれがあると、
7:52 AM
動的なタプルの場合は動的な処理としてさっきのmapが動かせて
7:52 AM
もし入力元のタプルの型が静的にわかっているときは、
7:53 AM
静的解析で結果のタプルの型がわかる。
7:54 AM
$0.first は、 $0 の型がわかっている(<A>(A) -> BA が特定できる)ときには、 .first の型が静的にわかるけどそれは、 .firstassociatedtype を与えているprotocolがあって、それを個別の A が充足してる typealias が静的に見えるから、です。
7:56 AM
任意の x.y の形の式に対して、 x の型があるプロトコルで制約されていて、 y がそのプロトコルのメンバなのであれば、 x.y は静的に具体的な型が決定できる式、って事になりそう。
7:56 AM
x だけのときは <A>(A) -> A まあつまり <Self>(Self) -> Selfとして同じことが言える。
7:58 AM
式が複雑になって?そうじゃないものが式の中に混ざり込んだ時は、静的に決定できない式になって、 タプルのmapとしては、全部の要素の型が同じタプルになっちゃう。
7:58 AM
そうじゃないものって存在しない気がするな?
8:00 AM
必ず何らかの式の型はあるから型は決定できるけど、 <A>(A) -> BB が <A> を充足する個別の T に対して静的に解決できる型の場合と <A> に入る T がなんであろうが固定の型になっちゃう場合 ( description($0) など )がある。
8:01 AM
この、個別に異なりえて、かつそれが静的に決定できる場合と、 そうでなくて固定になっちゃう場合が、またなんかちゃんと述べられる気がする。
8:01 AM
やっぱ <A>(A) -> <B>B<A>(A) -> B の違いなんじゃないか??
8:03 AM
なぜなら、 map に <A>(A) -> B を与えたらそりゃ結果は (B, B, B, ...) でしか無いはずなので。
8:04 AM
で、結果の型は、呼び出し側から決定できるわけじゃないから、リバースジェネリックパラメータがあるってことになりそう。