在不同 return 类型的情况下克服 Scala 中的类型擦除
Overcoming type erasure in Scala in cases of different return types
我想定义以下两个 Scala 函数:
def Pr(
f: Int => Int,
g: Tuple3[Int, Int, Int] => Int
): Tuple2[Int, Int] => Int = {
def recurse(x: Int, counter: Int): Int = counter match {
case 0 => f(x)
case y => g(x, y-1, recurse(x, y-1))
}
(recurse _).tupled
}
def Pr(
f: Tuple2[Int, Int] => Int,
g: Tuple4[Int, Int, Int, Int] => Int
): Tuple3[Int, Int, Int] => Int = {
def recurse(x1: Int, x2: Int, counter: Int): Int = counter match {
case 0 => f(x1, x2)
case y => g(x1, x2, y-1, recurse(x1, x2, y-1))
}
(recurse _).tupled
}
这里的基本思想是,如果f
是n元,g
是(n+2)元,那么Pr(f,g)
是(n+1)元.当然,问题是类型擦除。类型擦除后 f
和 g
都是 Function1
的,两个 Pr
函数是无法区分的。我认为创建一个带有类型标签的 Pr
函数可能会有所帮助,但我不确定如何在每种情况下更改 return 类型。
乐于接受任何建议;那些可以在不使用额外的库(Shapeless,Scalaz)的情况下解决这个问题的是首选。
对于另外 5%,标准习惯用法(早于磁化)是添加一个虚拟隐式参数列表:
def Pr(
f: Tuple2[Int, Int] => Int,
g: Tuple4[Int, Int, Int, Int] => Int
)(implicit dummy: DummyImplicit): Tuple3[Int, Int, Int] => Int = {
def recurse(x1: Int, x2: Int, counter: Int): Int = counter match {
case 0 => f(x1, x2)
case y => g(x1, x2, y-1, recurse(x1, x2, y-1))
}
(recurse _).tupled
}
肯定有无数的问答。
Scala 重载只考虑第一个参数列表;虚拟参数用于消除已擦除签名的歧义。
模重载是邪恶的,Travis Brown 的博客是关于在 Scala 中做一些你可能不应该做的不可能的事情,他说这可能不是一件好事。全面披露,tl;博士
我想定义以下两个 Scala 函数:
def Pr(
f: Int => Int,
g: Tuple3[Int, Int, Int] => Int
): Tuple2[Int, Int] => Int = {
def recurse(x: Int, counter: Int): Int = counter match {
case 0 => f(x)
case y => g(x, y-1, recurse(x, y-1))
}
(recurse _).tupled
}
def Pr(
f: Tuple2[Int, Int] => Int,
g: Tuple4[Int, Int, Int, Int] => Int
): Tuple3[Int, Int, Int] => Int = {
def recurse(x1: Int, x2: Int, counter: Int): Int = counter match {
case 0 => f(x1, x2)
case y => g(x1, x2, y-1, recurse(x1, x2, y-1))
}
(recurse _).tupled
}
这里的基本思想是,如果f
是n元,g
是(n+2)元,那么Pr(f,g)
是(n+1)元.当然,问题是类型擦除。类型擦除后 f
和 g
都是 Function1
的,两个 Pr
函数是无法区分的。我认为创建一个带有类型标签的 Pr
函数可能会有所帮助,但我不确定如何在每种情况下更改 return 类型。
乐于接受任何建议;那些可以在不使用额外的库(Shapeless,Scalaz)的情况下解决这个问题的是首选。
对于另外 5%,标准习惯用法(早于磁化)是添加一个虚拟隐式参数列表:
def Pr(
f: Tuple2[Int, Int] => Int,
g: Tuple4[Int, Int, Int, Int] => Int
)(implicit dummy: DummyImplicit): Tuple3[Int, Int, Int] => Int = {
def recurse(x1: Int, x2: Int, counter: Int): Int = counter match {
case 0 => f(x1, x2)
case y => g(x1, x2, y-1, recurse(x1, x2, y-1))
}
(recurse _).tupled
}
肯定有无数的问答。
Scala 重载只考虑第一个参数列表;虚拟参数用于消除已擦除签名的歧义。
模重载是邪恶的,Travis Brown 的博客是关于在 Scala 中做一些你可能不应该做的不可能的事情,他说这可能不是一件好事。全面披露,tl;博士