基于return类型的Scala类型参数推断(函数vs方法)
Scala type parameter inference based on return type (function vs method)
我尝试在 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
函数不起作用而方法起作用?看起来问题在于推理仅基于 return 类型。例如,我可以 isEmpty
而不是 contains
而不是参数,这再次与 matches
方法一起使用但不是函数。
完整的代码清单在gist。
你需要的是将参数分成两个列表:
def matches[A](x: A)(m: Matcher[A]) = m(x)
matches(Option(1))(contains(1))
matches(Seq(1,2))(contains(1))
A
从 x
推断出来,然后在 type-checking m
时可用。 Mather2Any
你有同样的情况。
旁注:经常有人问到这个问题的变体,我只是发现回复比找到重复的更快。
我尝试在 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
函数不起作用而方法起作用?看起来问题在于推理仅基于 return 类型。例如,我可以 isEmpty
而不是 contains
而不是参数,这再次与 matches
方法一起使用但不是函数。
完整的代码清单在gist。
你需要的是将参数分成两个列表:
def matches[A](x: A)(m: Matcher[A]) = m(x)
matches(Option(1))(contains(1))
matches(Seq(1,2))(contains(1))
A
从 x
推断出来,然后在 type-checking m
时可用。 Mather2Any
你有同样的情况。
旁注:经常有人问到这个问题的变体,我只是发现回复比找到重复的更快。