基于返回类型的Scala类型参数推断(函数与方法)

时间:2018-03-02 13:39:21

标签: scala type-inference typeclass scala-implicits

我尝试在Scala中创建一个小型匹配库。 我有以下类型表示匹配类型T的约束的匹配器:

trait Matcher[-T] extends (T => Boolean)

matches函数,用于检查该约束是否适用于给定实例:

def matches[A](x: A, m: Matcher[A]) = m(x)

有了这个,我希望能够写出如下的支票:

matches(Option(1), contains(1))
matches(Seq(1,2), contains(1))

contains可以在任何容器上抽象。我使用类型类尝试了以下抽象:

trait F[-C[_]] {
  def contains[A >: B, B](c: C[A], x: B): Boolean 
}

然后我可以用来定义contains函数:

def contains[A, B[A]](y: A)(implicit f: F[B]): Matcher[B[A]] = new Matcher[B[A]] {
  override def apply(v1: B[A]): Boolean = f.contains(v1, y)
}

有两个隐式定义,一个用于Option

implicit object OptionF extends F[Option] {
  override def contains[A >: B, B](c: Option[A], x: B): Boolean = c.contains(x)
}

Iterable

implicit object IterableF extends F[Iterable] {
  override def contains[A >: B, B](c: Iterable[A], x: B): Boolean = c.exists(_ == x)
}

但是,当我在每次调用matches时收到错误时。它们都是一样的:

Error:(93, 39) ambiguous implicit values:
both object OptionF in object MatchExample of type MatchExample.OptionF.type
and object IterableF in object MatchExample of type MatchExample.IterableF.type
match expected type MatchExample.F[B]
matches(Option(1), contains(1))

似乎类型推断无法正确推断出类型,这就是两个隐式匹配的原因。

如何在没有歧义的情况下定义matches函数?

我还尝试使用隐式转换将matches函数直接添加到任何类型:

implicit class Mather2Any[A](that:A) {
  def matches(m: Matcher[A]): Boolean = m(that)
}

这很好用:

Option(x1) matches contains(x1)
lx matches contains(x1)
lx matches contains(y1)

我不明白为什么matches函数在方法不起作用时不起作用?看起来问题是推理仅基于返回类型。例如,我可以contains而不是isEmpty而不是matches方法但不起作用的参数。

完整的代码列表位于此gist

1 个答案:

答案 0 :(得分:0)

您需要将参数拆分为两个列表:

def matches[A](x: A)(m: Matcher[A]) = m(x)

matches(Option(1))(contains(1))
matches(Seq(1,2))(contains(1))

Ax推断,然后在类型检查m时可用。使用Mather2Any您的情况相同。

附注:经常会询问此变体,我发现回复要快于找到副本。