2017-04-22 47 views
0

我試圖在scala中創建一個圍繞scala函數的文檔包裝器,以便可以查詢包裝器的包含函數的文檔,如下所示:Scala類型推斷不能與類型邊界一起工作,除非明確指定類型

trait WrappedFunction1[A, B] { 
    def f : Function1[A, B] 
    def doc: String 
    def apply(x:A):B = f(x) 
    def compose[C, T <:WrappedFunction1[B, C]](that:T):WrappedFunction1[A, C] = 
    new Wrapper[A, C](this.f andThen that.f, this.doc + " composed with " + that.doc) 
} 

class Wrapper[A, B](f1:Function1[A, B], sos:String) extends WrappedFunction1[A, B] { 
    val f = f1 
    val doc = sos 
} 

object Wrapper { 
    implicit class Wrap[A, B](f1:Function1[A, B]) { 
    def wrap(sos:String):WrappedFunction1[A, B] = new Wrapper(f1, sos) 
    } 
} 

以下是我會使用這樣的:

import Wrapper._ 
val x : String => String = _.toLowerCase 
val y : String => String = _.toUpperCase 
val x1 = x.wrap("a function for lowercasing") 
val y1 = y.wrap("a function for uppercasing") 

println(x1("LOL")) // lol 
println(x1.doc) // a function for lowercasing 

但是,我不能得到的類型推斷當我撰寫的這兩個:

val xy = x1 compose y1 

cmd3.sc:1: inferred type arguments [Nothing,cmd3Wrapper.this.cmd1.cmd0.wrapper.WrappedFunction1[String,String]] do not conform to method compose's type parameter bounds [C,T <: cmd3Wrapper.this.cmd1.cmd0.wrapper.WrappedFunction1[String,C]] 
val xy = x1 compose y1 
      ^cmd3.sc:1: type mismatch; 
found : cmd3Wrapper.this.cmd1.cmd0.wrapper.WrappedFunction1[String,String] 
required: T 
val xy = x1 compose y1 
        ^
Compilation Failed 

撰寫,如果我明確規定的各類作品他們:

val xy = x1 compose[String, WrappedFunction1[String, String]] y1 

有沒有什麼地方我會錯了嗎? 也有更好的方法來做到這一點? (我試過typeclasses,但它們似乎被定義爲具有一個類型參數的特徵,也許是任何其他代數數據類型?)

回答

1

問題在於Scala類型推斷的細節。它不能首先推斷出T,然後從中推斷出C;相反,它必須一次推斷出兩者。

that: T它可以確定T,但C沒有在參數類型所提到的,所以它的分配Nothing只有對下一步的編譯器會發現它不適合。因此,解決方法是將類型更改爲

def compose[C, T <:WrappedFunction1[B, C]](that: T with WrappedFunction1[B, C]) 

或者更好,只需

def compose[C](that: WrappedFunction1[B, C]) 

,因爲這已經允許通過的WrappedFunction1[B, C]任何亞型!