问题描述
class OptionLikeMatcher[F[_],T,U](typeName: String,toOption: F[T] => Option[U]) extends Matcher[F[T]] { ... }
case class RightMatcher[T]() extends OptionLikeMatcher[({type l[a]=Either[_,a]})#l,T]("Right",(_:Either[Any,T]).right.toOption)
case class LeftMatcher[T]() extends OptionLikeMatcher[({type l[a]=Either[a,_]})#l,T]("Left",(_:Either[T,Any]).left.toOption)
有人可以解释他们在这里试图用类型参数实现什么吗?
toOption: F[T] => Option[U]
参数在用于 RightMatcher
和 LeftMatcher
时具有什么类型?
它来自 Scala Specs2 库。
解决方法
让我们首先解决这里最复杂的类型构造函数:
({type l[a]=Either[_,a]})#l
是对类型 lambdas 进行编码的原始方式。可以更简洁地写成
Either[_,?]
with kind-projector,or as
[X] =>> Either[_,X]
在 Scala 3 中,它基本上只是选择 Either
的右侧参数作为相关参数,并用通配符替换左侧参数。
现在,OptionLikeMatcher
的三个类型参数是:
-
F[_]
- 被匹配事物的类型构造器;预计它的行为与Option
“有点相似”,即应该有某种方法可以从中获得Option
。 -
T
是插入到F
类型构造函数中的类型;F[T]
一起给出了匹配的类型。 -
U
可以被认为是T
的“轻微扰动”版本;它捕获的信息与T
基本相同,但在将F[T]
转换为Option[U]
时允许一些受控的草率(否则,如果需要F[T] => Option[T]
,那实际上与要求称为自然变换F ~> Option
的相当严格的结构相同,在这种情况下可能过于严格)。
将它们放在一起得到 RightMatcher
:
-
F[A] = Either[_,A]
- 即选择Either
的右侧参数,忽略左侧参数 - 来自
T
的OptionLikeMatcher
绑定到来自T
的RightMatcher
-
U
中的OptionLikeMatcher
也绑定到T
中的RightMatcher
,即此处不使用“轻微扰乱”T
的可能性,T
中的U
和OptionLikeMatcher
均由相同类型实例化。
因此,toOption
中的 RightMatcher
具有 Either[_,T] => Option[T]
类型。 (_:Either[Any,T]).right.toOption
符合Either[_,T] => Option[T]
,因为Any
出现在Either
内的协变位置,而Either[Any,T]
出现在函数类型内的逆变位置,所以Either[Any,T] => Option[T]
是 Either[_,T] => Option[T]
的子类型,因为它的输入类型更加宽松,可以在需要 Either[_,T] => Option[T]
的任何地方使用。
说了这么多,我找不到任何 F
形状不是 F[T]
的应用程序(既不在 OptionLikeMatcher
中,也不在 OptionLikeChekedMatcher
中),所以似乎他们将输入类型拆分为类型构造函数 F
和类型参数 T
,只是为了稍后将它们用作不可分割的单元 F[T]
。也许这是从一些更复杂的构造重构后遗留下来的。
当用于 toOption: F[T] => Option[U]
和 RightMatcher
时,LeftMatcher
参数具有什么类型
也许具体的演练会有所帮助。让我们考虑将类型参数 RightMatcher[Int]()
实例化为 T
的 Int
。这给了我们
F = ({type l[a]=Either[_,a]})#l
T = Int
U = T = Int
并将上述类型实例化插入
toOption: F[T] => Option[U]
我们得到
toOption: (({type l[a]=Either[_,a]})#l)[Int] => Option[Int]
简化为
toOption: Either[_,Int] => Option[Int]
让我们再练习一次 LeftMatcher[String]()
。我们有
F = ({type l[a]=Either[a,_]})#l
T = String
U = T = String
并将上述类型实例化插入
toOption: F[T] => Option[U]
我们得到
toOption: (({type l[a]=Either[a,_]})#l)[String] => Option[String]
简化为
toOption: Either[String,_] => Option[String]