我有一个类Foo
,它将类型构造函数F
作为类型参数:
case class Foo[F[_]](x: F[String])
现在我想定义一个仅适用的成员方法bar
,如果F[T] = Outer[Inner[T]]
用于某些固定的外部类型Outer
,例如Option
:
def bar[Inner[_]](implicit ev: ???): Foo[Inner]
???
必须是自然变换F ~> Outer·Inner
,·
是类型构造函数的组合。
另外如何最好地编写类型构造函数的组合?我目前使用lambda ({type L[X] = Outer[Inner[X]]})#L
类型编写。
答案 0 :(得分:3)
我不认为ScalaZ中定义了一个,但是以scalaz.Leibniz
为模板制作一个相当简单。我不会专注于构图和便利方法,只能获得实质内容:
sealed abstract class LeibnizK[F[_], G[_]] {
def subst[Z[_[_]]](p: Z[F]): Z[G]
}
object LeibnizK {
implicit def refl[F[_]] = new LeibnizK[F, F] {
override def subst[Z[_[_]]](p: Z[F]): Z[F] = p
}
}
这似乎是你正在寻找的暗示:
type Outer[A] = Option[A]
type Id[A] = A
case class Foo[F[_]](me: F[String]) {
// Oh boy, here comes type lambda
def bar[Inner[_]](implicit leibk: LeibnizK[
F,
({type L[A] = Outer[Inner[A]]})#L
]): Outer[Foo[Inner]] = leibk.subst(this).me.map(Foo(_)) // <- OK to use methods of Outer
}
assert(Foo[Option](Some("meh")).bar[Id] == Some(Foo[Id]("meh")))
查看kind projector编译器插件。它允许你写:
λ[A => Outer[Inner[A]]
// or
Lambda[A => Outer[Inner[A]]
而不是
({type L[A] = Outer[Inner[A]]})#L
对于简单的情况(没有嵌套),语法甚至更短
(?, Int)
而不是
({type L[A] = (A, Int)})#L