Scala中可以使用以下内容:
scala> val l = List
l: scala.collection.immutable.List.type = scala.collection.immutable.List$@7960c21a
scala> l ( 1, 2, 3 )
res0: List[Int] = List(1, 2, 3)
换句话说,Scala具有更高阶的多态性。我想使用高阶多态来执行以下操作。
sealed abstract class A { def eval () : A }
case class A0 () extends A { ... }
case class A1 ( a : A ) extends A { ... }
case class A2 ( a : A, b : A ) extends A { ... }
....
所以我有一堆case类,A
的子类,其构造函数不一定采用相同数量的参数。我也希望有一个“通用”案例类,如下所示:
case class ApplyA ( c : ???, l : List [ A ] ) extends A {
def eval () : A = { ??? } }
这个想法是ApplyA
将第一个参数作为A
子类型的构造函数和参数列表。然后eval
方法使用构造函数构造一个适当的类(如果可能)(即列表具有正确的长度)并返回它
(这对应于上面l ( 1, 2, 3)
示例中的List
)。 ApplyA
的第一个构造函数的参数类型是什么?
这应该可以使用更高阶的多态性,但我无法弄清楚如何。我知道即使不使用高阶多态,只需在函数中包装构造函数,然后将这些函数作为第一个参数传递给ApplyA
的构造函数,我就可以做到这一点,但我想了解如何使用更高的函数 - 直接命令多态。
答案 0 :(得分:12)
@alexey_r非常正确,您的List
示例不涉及更高阶的多态性。但是如果你准备使用一些type-level heavy artillery,你可以抽象出A{0,1,2}
构造函数的arity来获得看起来非常接近你所要求的东西。
要注意的第一点是,正如所写,你的'通用'类不可能实现,
case class ApplyA(c : ???, l : List[A]) ...
因为构造函数c
的arity与列表l
的长度之间没有编译时可检查的关系。我们可以通过将List
替换为HList
并帮助自己从具有任意arity的普通函数转换为具有单个HList
参数的函数来解决该问题,
import shapeless.HList._
import shapeless.Functions._
sealed abstract class A { def eval() : A }
case class A0 () extends A { def eval() = this }
case class A1 ( a : A ) extends A { def eval() = this }
case class A2 ( a : A, b : A ) extends A { def eval() = this }
case class ApplyA[C, L <: HList, HF](c : C, l : L)
(implicit hl : FnHListerAux[C, HF], ev : HF <:< (L => A)) extends A {
def eval () : A = hl(c)(l)
}
val a : A = A0()
val a0 = ApplyA(A0.apply _, HNil)
val a1 = ApplyA(A1.apply _, a :: HNil)
val a2 = ApplyA(A2.apply _, a :: a :: HNil)
隐式参数hl : FnHListerAux[C, HF]
提供从构造函数(无论它是什么)到单个HList参数的函数的转换。隐式参数ev : HF <:< (L => A)
证明提供的HList
构造函数参数的长度具有正确的长度(并且类型为FWIW,但在此示例中几乎不相关)。
答案 1 :(得分:9)
问题是List
示例根本不涉及任何高阶多态。 List.apply
只需要可变数量的参数:
def apply(xs: A*)
高阶多态包含将类型构造函数作为类型参数的方法或类型,例如
def fmap[F[_], A](x: F[A]): F[B]
所以不,你不能使用高阶多态。