为一元类型构造函数键入类模式

时间:2017-01-14 09:57:18

标签: scala typeclass higher-kinded-types

给出以下类型类定义:

*

我能够为类型Int的nullary类型构造函数创建实现(想象StringBooleanimplicit object IntAttributeParser extends AttributeParser[Int] { override def parse(attribute: String): Int = ??? } 等等:

* -> *

我还想为类List[T]的一元类型构造函数实现这些解析器(想象Option[T]implicit object OptionAttributeParser extends AttributeParser[Option] 等),但当前定义失败的原因显而易见:

Option

给出:

  

Option[T]采用类型参数

由于我们需要指定AttributeParser,但这是不可能的,因为TT[_]定义,而不是Option[T]

一种可能的解决方案是为每个type OptionInt = Option[Int] 类型定义类型别名,例如:

implicit object OptionIntParser extends AttributeParser[OptionInt] {
  override def parse(node: Node, attribute: String): OptionInt = ???
}

然后编译器很高兴:

Option[T]

但这会迫使我创建一个类型别名,而不是一般为所有*定义解决方案。

是否有任何解决方案可以将* -> *AttributeParser[T]这两种类型传递给类型类定义?

修改

我最初假设AttributeParser[Int]对于类型构造函数来说是种类*当然是错误的。 * -> *仍然是{{1}}种类型的构造函数。

2 个答案:

答案 0 :(得分:2)

我没有看到编译器拒绝您的更高类Option[_]的原因:

implicit object OptionAttributeParser extends AttributeParser[Option[_]] { ... }

它将类型构造函数从* -> *更改为(* -> *) -> *,是的,但编译器会将这两种情况视为"某些类型为in,某些类型为"。就像你可以指定例如Option[Set[_]]

请注意,当您开始实施Option[_]时,OptionAttributeParser是不够的:

implicit object OptionAttributeParser extends AttributeParser[Option[_]] {
  override def parse(attribute: String): Option[_] = ???
}

def foo[A : AttributeParser](p: A) = p

foo(Option(42))
  

无法找到类型的证据参数的隐含值   AttributeParser[Option[Int]]

但这很容易解决:

implicit def optionAttributeParser[T] = new AttributeParser[Option[T]] {
  override def parse(attribute: String): Option[T] = ???
}

def foo[A : AttributeParser](p: A) = p

foo(Option(42)) // Some(42)

答案 1 :(得分:2)

解决方案是通过def的多态实例,它可能如下所示:

implicit def optionAttributeParser[T](implicit parser: AttributeParser[T]) =
  new AttributeParser[Option[T]] {
    def parse(attribute: String): Option[T] =
      if (attribute.isEmpty) None else Some(parser.parse(attribute))
  }

有时候,更通用的模式会用于更高级的类型,例如cats.MonoidK  在您的情况下,您可以定义更高级别的类型类

trait AttributeParserK[F[_]] {
  def parseK[T](attribute: String)(implicit itemParser: AttributeParser[T]): F[T]
}

并在实例范围中包含一些其他实例

object AttributeParser{
  implicit def kindParser[F[_], T](implicit itemParser: AttributeParser[T], parserK: AttributeParserK[F]) =
    new AttributeParser[F[T]] {
      def parse(attribute: String): F[T] = parserK.parseK(attribute)
    }
}