2016-12-18 15 views
4

だから私はちょっと遊んでいて、存在と分散に関する何かを書こうとしていました。この興味深いコードが出てきました。なぜコンパイラはV [+ _]に対してV [U] <: T => V [U] =>(_ <:V [_ <:U])を計算できないのですか?

final case class Box[+T](val value: T) { 
    def >>=[U](f: T => Box[U]) = f(value) 
    def flatMap[U](f: (_ >: T) => (_ <: Box[_ <: U])): Box[U] = this >>= f 
} 

は、これはコンパイルに失敗します。

(_ >: T) => (_ <: Box[_ <: U])T => Box[U]のサブタイプではないので、私は、奇妙な見つける
Variance.scala:3: no type parameters for method >>=: (f: T => Box[U])Box[U] exist so that it can be applied to arguments (_$1 => _$2) 
--- because --- 
argument expression's type is not compatible with formal parameter type; 
found : _$1 => _$2 where type _$2 <: Box[_ <: U], type _$1 >: T 
required: T => Box[?U] 
    def flatMap[U](f: (_ >: T) => (_ <: Box[_ <: U])): Box[U] = this >>= f 
                   ^
Variance.scala:3: type mismatch; 
found : _$1 => _$2 where type _$2 <: Box[_ <: U], type _$1 >: T 
required: T => Box[U] 
    def flatMap[U](f: (_ >: T) => (_ <: Box[_ <: U])): Box[U] = this >>= f 
                    ^

Function1は最初の型パラメーターで反変的なので、これはT => (_ <: Box[_ <: U])のサブタイプです。 Function1は結果型で共変なので、これはT => Box[_ <: U]のサブタイプであり、Boxはそのパラメータに共変なので、サブタイプはT => Box[U]ではありませんか?

不思議なことに、型帰属を「ヒント」f: T => Box[U]はそれがコンパイル可能コンパイラで

// This change is not required ;) 
type Box[T] = `What A Category Theorist Calls "The Identity Monad" And What Everyone Else Calls "A Box"`[T] 
final case class `What A Category Theorist Calls "The Identity Monad" And What Everyone Else Calls "A Box"`[+T](val value: T) { 
    def >>=[U](f: T => Box[U]) = f(value) 
    def flatMap[U](f: (_ >: T) => (_ <: Box[_ <: U])): Box[U] = this >>= (f: T => Box[U]) 
} 

にコードを変更します。暗黙的な変換や変数宣言がないので、これで違いはありませんか?私はこれをコンパイルし得ることの発見

他の方法は、これは私が問題はコンパイラがそれに(_ >: T) => (_ <: Box[_ <: U]) <: T => Box[U]多くはできないことになっ苦労して以下であると信じています

def flatMap[U](f: (_ >: T) => (_ <: Box[_ <: U])): Box[U] = this.>>=[U](f) 

を書いていますエラーメッセージに暗示されているように見える>>=の型パラメータを推測します。

(SBTとのScala 2.12.1を(使用して、それが何かを変更した場合))

答えて

0
final case class Box[+T](val value: T) { 
    def >>=[U](f: T => Box[U]) = f(value) 
    def flatMap[U](f: (_ >: T) => (_ <: Box[_ <: U])): Box[U] = this >>= f 
} 

flatMap retrunタイプはBox[U]ですが、this >>= fを使用します。

したがって>>=fタイプ(_ >: T) => (_ <: Box[_ <: U])に自動的に変更されます。

したがってBox[(_ >: T) => (_ <: Box[_ <: U])]は一致しませんBox[U]です。

私はあなたがそのように変更することができると思う:
def flatMap[U](f: (_ >: T) => (_ <: Box[_ <: U])): Box[U] = this >>=[U] f

+0

私は、コードの仕事を作る方法を知っています。なぜなら、 '_ <:Box [_ <:U]' *は 'Box [U]'とマッチしなければならないからです。私は '[U]'を '>> ='に加えるとコンパイルできることを知っています。 – HTNW

+0

理由は 'Box [(_>:T)=>(_ <:Box [_ <:U]) ''不一致 'Box [U]' –

+0

あなたは 'Box [ T)=>(_ <:Box [_ <:U])] '? – HTNW

関連する問題