ログインしてさらにmixiを楽しもう

コメントを投稿して情報交換!
更新通知を受け取って、最新情報をゲット!

ScalaコミュのLower Type boundsについて

  • mixiチェック
  • このエントリーをはてなブックマークに追加
ちなみに今LiftのMaybeモナドであるCanクラスの定義の意味合いを調べています
メソッドの定義のLower Type boundsの部分でなぜそれをするのか?にはまっています。
#コンパイルのエラーがでるという理由に関しては、下記のありがたいサイトで解決
 済みなのですが・・・
http://jijixi.azito.com/cgi-bin/diary/index.rb?date=20060414

そもそも、作者がこれを[B >: A]を入れる意図というのはなんだったのか?
何がしたかったのかというのがよくわからなくなりました。

例えばCanクラスは下記の定義があります。

class Can[+A]{
def openOr[B >: A] (default:B) :B = default
:中略
}

このクラスのCan[+A]と書いている「A」とメソッドのopenOrの「A」は別モノ
なのでしょうか?

もしそうであるならば、

scala> class Can[+A]{
| def openOr(default:A) :A = default
| }
といったふうに定義すると
---------------
<console>:6: error: covariant type A occurs in contravariant position in type A
of value default
def openOr(default:A) :A = default
^
---------------
とエラーが出ます。これはどういうことなんでしょう?
エラーが出る理由はこのありがた〜いページにあり納得しましたが・・・

http://jijixi.azito.com/cgi-bin/diary/index.rb?date=20060414

しかし、そもそも[B >: A]を定義した理由は単純にエラーになるから
だけなんでしょうか?例えば

class Person
class GoodPerson extends Person;
--------------------
scala> var a = new Can[GoodPerson]();
a: Can[GoodPerson] = Can@14b2d2d

scala> a.openOr(new GoodPerson());
res30: GoodPerson = GoodPerson@13d0953
scala> a.openOr(new Person());
res31: Person = Person@59a6b5
scala> a.openOr("String");
res32: java.lang.Object = String

→ええ!Stringでもええわけ?制限ないんや!

scala> a.openOr[GoodPerson](new Person());
<console>:8: error: type mismatch;
found : Person
required: GoodPerson
a.openOr[GoodPerson](new Person());
^
scala> a.openOr[Person](new GoodPerson());
res34: Person = GoodPerson@14ddd67
scala> a.openOr[Person](new Person());
res35: Person = Person@14ce1fd
scala> a.openOr[Person]("String");
<console>:7: error: type mismatch;
found : java.lang.String("String")
required: Person
a.openOr[Person]("String");

メソッドのほうにも明示的にPersonとか入れると
それっぽい動きに・・・

^
ためしに

scala> var b = new Can[String]();
b: Can[String] = Can@1b56b0b

scala> b.openOr[Person](new Person());
<console>:7: error: type arguments [Person] do not conform to method openOr's ty
pe parameter bounds [B >: String]
b.openOr[Person](new Person());
^
とやるとしっかりエラー。クラスの定義[+A]と関係なくもなさそう。。。

ますます深みにはまってきました。

いったい
class Can[+A]{
def openOr[B >: A] (default:B) :B = default
:中略
}

のopenOrの[B >: A]定義は何がしたいんでしょう?戻り値を限定
するわけでもなく、作者が何をしたいのか理解できなくなってきました。
#単に戻り値にAと同じ型を返したいから(でも強制力はない)ですかね?

なんだか良く分からなくなってきました。
何かお知恵のある人はコメント戴けるとうれしいです。
#私の理解不足だけかもですが。

コメント(3)

こんにちは。

> いったい
> class Can[+A]{
> def openOr[B >: A] (default:B) :B = default
> :中略
> }

まず、端的に目的を言うと、二つの型XとYについて、X <: Yであるとき(XがYのサブタイプである
とき)に、型安全性を壊さずに、Can[X] <: Can[Y]として扱いたい、ということです。そうすると、
たとえば、Can[Any]とCan[String]という二つの型があったとき、Can[Any]型が要求されている
箇所(変数の代入や仮引数への束縛など)に対して、Can[String]を渡すことができるようになります。
しかし、ただ単に

class Can[+A] {
def openOr(default :A) :A = default
}

とするのは、型の整合性上問題があるので、Scalaの処理系はこのようなコードをコンパイル
エラーにします(理由については、リンク先のサイトで書かれている通りです)。そこで、型エラーを
回避しつつ、A <: BならばCan[A] <: Can[B]になるようにするために、lower type boundsが必要に
なる、というわけです。

あと、

> scala> a.openOr("String");
> res32: java.lang.Object = String

> →ええ!Stringでもええわけ?制限ないんや!

については、型パラメータBがObjectと推論された結果なので
(つまり、a.openOr[Object]("String")という呼び出しだと推論された)、制限が無いというわけでは
無いです。
追記ですが、

> このクラスのCan[+A]と書いている「A」とメソッドのopenOrの「A」は別モノ
> なのでしょうか?

については、どちらのAも同じモノ(型パラメータ)を指しています。
素晴らしいご解説ありがとうございます。

めちゃくちゃわかりやすかったです!

むっちゃすっきりしました。

目的は

「X <: Yであるとき(XがYのサブタイプであるとき)に、型安全性を壊さずに、Can[X] <: Can[Y]として扱いたい」

ということにつきますね。

つまり上の例でいくと、

scala> var a = new Can(new Person());
a: Can[Person] = Can@1e27131

scala> a = new Can(new GoodPerson()); // 本来 Can[GoodPerson]の型である
a: Can[Person] = Can@325393

をしたいわけですね。わーい(嬉しい顔)
メソッドにばかり視点がいっていましたが、そういうことですね。

ログインすると、みんなのコメントがもっと見れるよ

mixiユーザー
ログインしてコメントしよう!

Scala 更新情報

Scalaのメンバーはこんなコミュニティにも参加しています

星印の数は、共通して参加しているメンバーが多いほど増えます。

人気コミュニティランキング