我正在尝试创建围绕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
我出错了吗?还有一个更好的方法吗?(我尝试了类型类,但似乎是针对具有一种类型param的特征定义的,也许是其他代数数据类型?(
问题在于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]
的任何子类型!