2017-04-22 34 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]任何亚型!