ScalaのHigher-kind Genericsについて

trait AttrHelper[+Holder[X]] というコードを例にして、ScalaのHigher-kind Genericsについて 説明してみる。
12
kmizu @kmizu

@pomu0325 なるほど。えーとですね、trait AttrHelper[+Holder[X]]のHolderってのはクラスそのものじゃなくて、「型パラメータを引数に取る何か」(通常、型コンストラクタと呼ばれます)を表す仮引数みたいなものなのです。(続く) #scala

2010-04-29 14:16:24
kmizu @kmizu

@pomu0325 で、Holderの実体はAttrHelperのユーザ(サブクラス含む)が与えます。先ほどの例では、Holder = Boxとして、HolderにBoxが束縛されているわけです。 #scala

2010-04-29 14:18:09
kmizu @kmizu

@pomu0325 あ、ちょうど行き違いだったようです。すいません。その通りで、型パラメータ名(のようなもの)です。Holder自体は型じゃないので、Javaのジェネリクスとかにおける通常の型パラメータとは少し違いますが。

2010-04-29 14:19:46
kmizu @kmizu

trait AttrHelper[+Holder[X]]の読み方解説してみる。 #scala

2010-04-29 14:21:23
🐶pomu0325 @pomu0325

@kmizu あー、すいません行き違いで。詳しい解説ありがとうございます。正確にはなんて呼ぶのでしょうか?→型パラメータ名

2010-04-29 14:21:36
kmizu @kmizu

まず、trait AttrHelperで、AttrHelperという名前のtraitを宣言している。ここまでは普通。 #scala

2010-04-29 14:21:56
kmizu @kmizu

で、[+Holder[X]]という部分だけど、ここが問題。通常のジェネリクスでは[G]あるいは[+G](covariantな場合)のようになるけど、[G[X]]のような形になっている。 #scala

2010-04-29 14:23:13
kmizu @kmizu

ここで、Holderは「型」ではなく、「ある型Xを型パラメータとして取って何かの型を作り出すもの」を表している、というのがポイント。関数の型っぽく書くと、* -> *みたいな。型を取って型を返す関数、のようなもの。 #scala

2010-04-29 14:25:28
kmizu @kmizu

つまり、AttrHelper[何か]の何かには通常の型(String,Intとか)は与えられなくて、「型を取って型を返す関数」のようなものしか与えられない。 #scala

2010-04-29 14:27:01
kmizu @kmizu

Listとかは、一つの型(String,Intとか)を引数に取って、別の型(List[String]とかList[Int])を返す関数のようなものとして見ることができるので、AttrHelper[List]みたいに書くことができる。 #scala

2010-04-29 14:29:08
kmizu @kmizu

あくまでAttrHelper[List]であって、AttrHelper[List[String]]とかじゃないのがポイント(List[String]だと普通の型になっちゃうので)。 #scala

2010-04-29 14:29:59
🐶pomu0325 @pomu0325

. @kmizu 高階関数の型パラメータ版みたいなもの? #scala

2010-04-29 14:30:13
kmizu @kmizu

このような、「型を受け取って型を返す何か」みたいなものを型コンストラクタと呼びます。ListとかArrayとかMapとかは全部型コンストラクタです。 #scala

2010-04-29 14:30:58
kmizu @kmizu

ちなみに、Javaのジェネリクスでも、java.util.Listとかjava.util.Mapとかは型コンストラクタなのですが、JavaではScalaのような高階のジェネリクスが無いので、意識する機会が無いのです。 #scala

2010-04-29 14:32:55
kmizu @kmizu

@pomu0325 Scalaの言語仕様書では型コンストラクタパラメータ(type constructor parameter)と呼んでいますね。他に一般的な呼び方も知らないので、とりあえずそんな感じで。 #scala

2010-04-29 14:35:47
kmizu @kmizu

@pomu0325 はい。そういうことです。 >高階関数の型パラメータ版みたいなもの?

2010-04-29 14:36:09
🐶pomu0325 @pomu0325

@kmizu カリー化みたいなことはできるんでしょうか? Mapの場合は、Hoge[+G[X,Y]] に Moge[Map] みたいに数合わせないとですよね? Hoge[G[X]]にMoge[Map[String, _]] みたいなイメージ。

2010-04-29 14:36:52
kmizu @kmizu

@pomu0325 鋭い指摘ですが、残念ながらカリー化はサポートされてないです。 #scala

2010-04-29 14:40:26
kmizu @kmizu

@pomu0325 カリー化をサポートするには、型コンストラクタに型パラメータを渡した結果がまた型コンストラクタになる、みたいなのが表現できないといけないのですが、これは現在のScalaの型システムでは表現できません。 #scala

2010-04-29 14:41:34
kmizu @kmizu

@pomu0325 ただし、カリー化でなく部分適用なら実は抽象型を型エイリアスを組み合わせればエミュレートすることができて、実際、そんなライブラリを作ってた人が居ます(ページは忘れましたが)。 #scala

2010-04-29 14:42:34
e(i(I),I). e(A+B,I):-e(A,J),e(B,K),I is J+K. @h_sakurai

@kmizu なるほど。うーん。Scalaジェネリックスはかなりの変態ですな。たぶん、う”、何だこれってならなくなりました。

2010-04-29 14:42:37
🐶pomu0325 @pomu0325

@kmizu なるほどー、大変勉強になりました! いつもありがとうございます。

2010-04-29 14:43:00
kmizu @kmizu

@h_sakurai 変態かと言われると、概念的には割と自然な拡張かなと個人的には思います。ちなみに、Haskellも同様の概念をサポートしています(OCamlは確か無かった…はず)。 #scala

2010-04-29 14:47:00