Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/18.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Scala:高阶函数参数类型中的多态性_Scala_Functional Programming - Fatal编程技术网

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)

我在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)  // 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