假设一个谓词是一个函数=>布尔值,我想为谓词实现一个Cats的"Contravariant Functor“类型类的实例。我还有一个隐式类PredicateOps,它定义了谓词的并集和交集运算符。
我已经能够使用类型别名让实例工作:
type Predicate[A] = A => Boolean
implicit val predicateContra = new Contravariant[Predicate] {
override def contramap[A, B](fa: Predicate[A])(f: B => A): Predicate[B] =
(b: B) => fa(f(b))
}但当我这样做时,我必须将所有谓词函数强制化为别名,如下所示:
val even: Predicate[Int] = (i: Int) => i % 2 == 0我觉得这很烦人。因此,我想知道是否可以直接为Function1定义从类型变量A到布尔值的predicateContra,而不是使用类型别名,但我无法让它工作。下面这两个想法都给了我一个编译器错误:
implicit val predicateContra = new Contravariant[Function1[_, Boolean]] {
// "Function1[_, Boolean] takes no type parameters, expected: one"
implicit def predicateContra[A] = new Contravariant[Function1[A, Boolean]] {
// "A => Boolean takes no type parameters, expected: one"我如何告诉编译器我的Function1的第一个参数应该保持为一个“洞”,而第二个参数应该被修复为布尔值?这有可能吗?看一下猫的源代码,我发现星号在很多地方都是类型参数,但这对我来说也不起作用。
发布于 2020-04-03 20:44:49
你可以使用kind projector,它允许你用一个星号(*)来表示“类型孔”。
这使得可以使用非常简单的语法来定义一种类型的* -> *,即一元类型构造函数(接受单个类型来生成类型)。例如,可以简单地将采用某个类型A来生成类型Map[A, Int]的类型编写为Map[*, Int]。
那么你的代码就变成了:
val strToBool: String => Boolean = _.contains("1")
val intToStr: Int => String = _.toString
def predicateContra =
new Contravariant[Function1[*, Boolean]] {
override def contramap[A, B](fa: A => Boolean)(f: B => A): B => Boolean =
(b: B) => fa(f(b))
}
predicateContra.contramap(strToBool)(intToStr)(42) // false
predicateContra.contramap(strToBool)(intToStr)(41) // true如果你不想使用额外的库,你可以在普通的Scala中通过使用lambda类型以一种更丑陋的方式来实现:
def predicateContra =
new Contravariant[({ type lambda[A] = Function1[A, Boolean] })#lambda] {
...
}https://stackoverflow.com/questions/61011524
复制相似问题