Scalaの型推論について

4
Keigo Imai @keigoi

Scalaといえば今週問題になったdef id[A]=(x:A)=>x のもとで id(id)(1) がまともに型推論されないのは何故なんだろう。Scala力低い

2011-11-27 09:52:05
Keigo Imai @keigoi

いまいちlocal type inferenceがよくわからなかったのでメソッドならうまくいくかもと思い def ap[A,B](f:A=>B,x:A) : B = f x として ap(id, 1) と試したがやはり型推論がうまくいかない。 なるほど、まだわからん

2011-11-27 10:53:41
Keigo Imai @keigoi

6.26.4 Local Type Inference, Case 3. Methods の 2番目のスキームに落ちて全てNothingに推論されている感じはあるのだけど、なぜ1番目の、「型パラメータを定数として扱い引数を型付けする」が失敗してるのか。まあいいや、またこんど

2011-11-27 11:07:47
Keigo Imai @keigoi

一つ目の例を見たらわかった… id(id) とした時点で外側のidの型引数が固定され、そいつのlower boundがないせいで内側の id の型引数が Nothingに固定されてしまうのか。型変数のまま上に伝播するわけではないのね。

2011-11-27 11:18:40
Keigo Imai @keigoi

def id[A >: Int]=(x:A)=>x としてAに下限を与えると、ap(id,1) は通る(当たり前?

2011-11-27 11:35:53
Keigo Imai @keigoi

生成された型変数が上に伝播せず、その場で制約を満たす具体的な型にinstantiateされる(っていったらいいのか何なのか)のはトップレベルに限った話ではないのだな

2011-11-27 11:39:01
Kenji Yoshida @xuwei_k

@keigoi 目的が推論の規則の話なので、求めてるものでないと思いますが、似たような関数でも def ap[A,B](x:A)(f:A=>B) = f(x) ってやると推論できます・・・というか、こうしないと推論されないですねたしかに #Scala

2011-11-27 11:43:56
Keigo Imai @keigoi

@xuwei_k ですねー。その場合 xに来るのはほとんどの場合単相なので普通に(?)推論されそうです。でもNilとかだとやはり引数型がNothingに落ちますねきっと。

2011-11-27 12:02:06
Keigo Imai @keigoi

型推論が一方向というのは、そういう意味だったんだな。

2011-11-27 12:38:50
kmizu @kmizu

@keigoi 一言で言うと、型パラメータの推論にあたっては、引数リスト(()で囲まれた部分)に関して、前から順に「引数リスト毎に」推論を行っているからです。

2011-11-27 12:45:09
kmizu @kmizu

@keigoi と、これだけだとわかりにくいと思いますので、もうちょっと突っ込んだ説明をば。 まず、id(id) の時点っで、引数として渡されるidはメソッドなので、関数への自動的なconversionが入ります。ご存知の通り(?)、Scalaでは「関数の値」は多相になれないので

2011-11-27 12:46:38
kmizu @kmizu

@keigoi 多相的じゃないなんらかの関数値に変換する必要があります。問題は、Scalaの現時点での型推論方式では、先ほど言ったように、「前から 順番に」引数リストを見て、型パラメータを確定させるので、A = Intという置き換えがその時点ではできないことです。

2011-11-27 12:48:06
kmizu @kmizu

@keigoi というわけで、Scala処理系はその時点でAを何にしたら良いかわからないので、うまく推論できないときのデフォルト推論結果として、 A = Nothingにしてしまいます。もちろん、その後の適用を見れば、 A = Intであることはわかるのですが

2011-11-27 12:49:33
kmizu @kmizu

@keigoi (現時点での)Scalaはその情報を見る前に型パラメータAの実際の型を確定させてしまうので、うまく推論されないです。

2011-11-27 12:50:24
Yasushi Abe @yasushia

http://t.co/3OGbsoQ1 なぜこれが動くのかわからなかったんだけど、http://t.co/6aFczR9W 引数リストの推論中にA,Bの関係が確定できるからなのかな

2011-11-27 12:55:14
Yasushi Abe @yasushia

Scalaの型推論で一番最初に違和感を感じて「弱い?」と思っていた理由が理解できた、気がする。

2011-11-27 12:58:12
kmizu @kmizu

@keigoi あああー。すみませぬ。既にご自身で答えを出された問題に、亀レスでしたorz

2011-11-27 13:15:04
Keigo Imai @keigoi

@kmizu とんでもない!理解がとても深まりました、部分式の型パラメータを確定させてからそのメソッド呼び出しの型を確定させるってことですね。

2011-11-27 13:34:59
kmizu @kmizu

@keigoi はい。もちろん、この推論方式ははっきり言って「賢くなく」て、Scalaの型システムの根本的な限界はあるにせよ、もうちょっと「賢い」型パラメータの推論はできると思います。ただ、中途半端に賢くすると、推論ルールがわかりにくくなる、というトレードオフはあるかなあと。

2011-11-27 15:06:03
kmizu @kmizu

@keigoi Oderskyらの研究者がそういう事を知らないわけが無いので、意図的にその辺は弱く(推論方法を単純化)してあるのだろうと思ってます。

2011-11-27 15:07:36
kmizu @kmizu

@yasushia @keigoi それが動作する理由はまた少し違いまして。Scala 2.8でimplicit推論ルールが追加されたことによるものです。端的に言うと、implicit引数の一部の型が未確定なときに、確定している型から逆方向に型パラメータを推論するルールです。

2011-11-27 15:52:46
kmizu @kmizu

@yasushia @keigoi 具体的には、このケースではimplicit parameterが渡される前にAの型パラメータがインスタンス化されて、それを元にimplicit parameterに使われている型パラメータBが推論されます。ちょっとややこしいですが。

2011-11-27 15:54:25
Yasushi Abe @yasushia

@kmizu まだちょっとよくわかってないんですが、最初のmagicの場合ではA,Bが同時に決定(インスタンス化?)しなければならないからBがNothing、implicitだとAとBの決定に時間差ができて、みたいな感じでしょうか。

2011-11-27 21:09:52
kmizu @kmizu

@yasushia だいたいそんな感じです。インスタンス化、という用語は、型パラメータに対して具体的な型を当てはめるときにしばしば使われる用語ですが、あまりなじみが無いかもしれません。ちょっとテキトーな説明を書いてみました。 http://t.co/KKdnqDmK

2011-11-27 21:33:12