繁体   English   中英

猫:为没有类型别名的谓词实现逆变?

[英]Cats: Implementing Contravariant for Predicates without a type alias?

假设谓词是 function A => Boolean,我想为谓词实现 Cats 的“逆变函子”类型 class 的实例。 我还有一个隐式 class 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

我觉得很烦人。 所以我想知道,除了使用类型别名,我是否可以直接为从类型变量 A 到 Boolean 的 Function1 定义 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 的第一个参数应该保持一个“洞”,而第二个应该固定为 boolean? 这甚至可能吗? 查看猫的源代码,我在很多地方发现了星号作为类型参数,但这对我也不起作用。

您可以使用kind projection ,它允许您使用星号 ( * ) 引用“类型孔”。

这使得定义类型* -> *的类型非常简单,即一元类型构造函数(采用单一类型来生成类型)。 例如,采用某种类型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

如果您不想使用额外的库,您可以使用 lambda 以一种更丑陋的方式在普通 Scala 中执行此操作:

def predicateContra =
  new Contravariant[({ type lambda[A] = Function1[A, Boolean] })#lambda] {
      ...
  }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM