给出以下类型类定义:
*
我能够为类型Int
的nullary类型构造函数创建实现(想象String
,Boolean
,implicit 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
,但这是不可能的,因为T
由T[_]
定义,而不是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}}种类型的构造函数。
答案 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)
}
}