Scala:高阶函数参数类型中的多态性
我在Scala中偶然发现了一些真正让我困惑的东西。高阶函数的参数类型似乎不是多态的。下面是我的意思的演示:Scala:高阶函数参数类型中的多态性,scala,functional-programming,Scala,Functional Programming,我在Scala中偶然发现了一些真正让我困惑的东西。高阶函数的参数类型似乎不是多态的。下面是我的意思的演示: class A class B extends A def call(f: A => A):A = f(new A) def A2A(a: A): A = new A def A2B(a: A): B = new B def B2A(b: B): A = new A def B2B(b: B): B = new B call(A2A) // Works call(A2B)
class A
class B extends A
def call(f: A => A):A = f(new A)
def A2A(a: A): A = new A
def A2B(a: A): B = new B
def B2A(b: B): A = new A
def B2B(b: B): B = new B
call(A2A) // Works
call(A2B) // Works
call(B2A) // Error!
call(B2B) // Error!
两个调用的错误消息相同:
<console>:12: error: type mismatch;
found : B => A
required: A => A
call(new B, B2A)
<console>:12: error: type mismatch;
found : B => B
required: A => A
call(new B, B2B)
callf需要一个函数,该函数可以接受a或任何子类型,并返回a或任何子类型。1和2起作用的原因是函数定义可以采用A或A的任何子类型,在1中,返回满足A的条件的A,在2中,返回满足A的子类型条件的B
后两者不起作用的原因是,您正在传递一个只能接受B并返回a或B的函数。要了解这是一个问题的原因,假设您有C类扩展a。B2A将无法处理C,这意味着根据定义,callf将无法处理输入C,尽管是a的子类型,但由于调用的定义,这是一个编译错误。callf需要一个可以接受a或任何子类型并返回a或任何子类型的函数。1和2起作用的原因是函数定义可以采用A或A的任何子类型,在1中,返回满足A的条件的A,在2中,返回满足A的子类型条件的B 后两者不起作用的原因是,您正在传递一个只能接受B并返回a或B的函数。要了解这是一个问题的原因,假设您有C类扩展a。B2A将无法处理C,这意味着根据定义,callf将无法处理输入C,尽管是a的子类型,但由于调用的定义,这是一个编译错误。Scala函数的参数是反变的。在A=>A的情况下,这意味着您可以创建一个接受A的超类型的函数,但不能创建一个接受B这样的子类型的函数 您可以定义一个函数,该函数可以采用以下任何形式: 功能1[-T1,+R] 的参数是逆变的,结果是协变的,这意味着在类型a=>a的函数中: 当a是结果类型协变时,可以返回B:A2B 当a是参数B2A和B2B的类型时,您不能接受a B,但是您可以像Any2A和Any2B一样传递a的超级类型。 关于函数的逆变和协变的一些解释可以在Scala函数的参数是逆变的中找到。在A=>A的情况下,这意味着您可以创建一个接受A的超类型的函数,但不能创建一个接受B这样的子类型的函数 您可以定义一个函数,该函数可以采用以下任何形式: 功能1[-T1,+R] 的参数是逆变的,结果是协变的,这意味着在类型a=>a的函数中: 当a是结果类型协变时,可以返回B:A2B 当a是参数B2A和B2B的类型时,您不能接受a B,但是您可以像Any2A和Any2B一样传递a的超级类型。
关于函数的逆变和协方差的一些解释可以在Ahh中找到,因此这是我的错误逻辑,而不是类型系统的怪癖Ahh,因此这是我的错误逻辑,而不是类型系统的怪癖谢谢你的回答,我选择了约束类型,而不是使用“查看我的编辑”。我只是使用“任何”来表示可以使用超级类型作为参数。谢谢您的回答,我选择约束类型,而不是使用“查看我的编辑”。我只是使用“任何”来表明可以使用超级类型作为参数。我认为您在B2A的结果类型的编辑中创建了一个类型。它应该是def B2Ab:B:A=新AI认为您在B2A结果类型的编辑中创建了一个类型。它应该是def B2Ab:B:A=新的A
trait ALike
class A extends ALike
class B extends A
def call[T <: ALike](t: T, f: T => A): A = f(t)
def A2A(a: A): A = a
def A2B(a: A): B = new B
def B2A(b: B): A = new A
def B2B(b: B): B = b
call(new A, A2A)
call(new A, A2B)
call(new B, B2A)
call(new B, B2B)
def Any2A(any: Any) = new A
def Any2B(any: Any) = new B
call(Any2A) // A = A@b5bddc9
call(Any2B) // A = B@62c1c65f