如何通过implicits分解类型构造函数?

时间:2017-01-13 12:31:25

标签: scala implicit scalaz shapeless higher-kinded-types

我有一个类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·是类型构造函数的组合。

  1. 这个隐含的参数怎么样?
  2. 我怎样才能从某处获得它?
  3. 如何编写类型构造函数组合?

    另外如何最好地编写类型构造函数的组合?我目前使用lambda ({type L[X] = Outer[Inner[X]]})#L类型编写。

1 个答案:

答案 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