简体   繁体   English

由一元类型构造函数限制的非一元类型构造函数

[英]Non-unary type constructor bounded by unary type constructor

The title is attempting to describe the following subtyping标题试图描述以下子类型

implicitly[Map[Int, String] <:< Iterable[(Int, String)]]

Type parameter A is inferred to (Int, String) here类型参数A在这里推断为(Int, String)

def foo[A](cc: Iterable[A]): A = cc.head
lazy val e: (Int, String) = foo(Map.empty[Int, String])

however attempting to achieve similar effect using type parameter bounds the best I can do is explicitly specifying arity of the type constructor like so但是尝试使用类型参数边界来实现类似的效果,我能做的最好的事情就是像这样显式指定类型构造函数的数量

def foo[F[x,y] <: Iterable[(x,y)], A, B](cc: F[A, B]): (A, B) = cc.head
lazy val e: (Int, String) = foo(Map.empty[Int, String])

because the following errors因为以下错误

def foo[F[x] <: Iterable[x], A](cc: F[A]) = cc.head
lazy val e: (Int, String) = foo(Map.empty[Int, String])
// type mismatch;
// [error]  found   : A
// [error]  required: (Int, String)
// [error]   lazy val e: (Int, String) = foo(Map.empty[Int, String])
// [error]                                  ^

Hence using Iterable as upper bound it seems we need one signature to handle unary type constructors Seq and Set , and a separate signature to handle 2-arity type constructor Map因此,使用Iterable作为上限似乎我们需要一个签名来处理一元类型构造函数SeqSet ,以及一个单独的签名来处理 2-arity 类型构造函数Map

def foo[F[x] <: Iterable[x], A](cc: F[A]): A                  // When F is Seq or Set
def foo[F[x,y] <: Iterable[(x,y)], A, B](cc: F[A, B]): (A, B) // When F is Map

Is there a way to have a single signature using type bounds that works for all three?有没有办法使用适用于所有三个的类型边界来获得单个签名? Putting it differently, how could we write, say, an extension method that works across all collections?换句话说,我们如何编写一个适用于所有 collections 的扩展方法?

I think the issue here is that F is set to Map , and kindness is wrong.我认为这里的问题是F设置为Map ,善良是错误的。 You would have to have say: I have some type X , that extends F[A] , so that when I upcast it, I can use it as F[A] - which in turn we want to be a subtype of Iterable[A].你不得不说:我有一些类型X ,它扩展了F[A] ,所以当我向上转换它时,我可以将它用作F[A] - 反过来我们希望成为 Iterable[A 的子类型]。 If we ask about it this way, it sounds hard.如果我们这样问,听起来很难。

Which is why I personally would just stay at:这就是为什么我个人会留在:

@ def foo[A](x: Iterable[A]): A = x.head
defined function foo

@ foo(List(1 -> "test"))
res24: (Int, String) = (1, "test")

@ foo(Map(1 -> "test"))
res25: (Int, String) = (1, "test")

"Give me any x that is an instance of Iterable[A] for A ". “给我任何作为Iterable[A] for A实例的x ”。

If I had to do some derivation... I would probably also go this way.如果我必须做一些推导......我可能也会用这种方式 go 。 I think this limitation is the reason CanBuildFrom works the way it works - providing matching for part of the type is hard, especially in cases like Map, so let's provide a whole type at once as a parameter, to limit the number of inference needed.我认为这个限制是CanBuildFrom以它的工作方式工作的原因 - 为部分类型提供匹配很困难,特别是在 Map 这样的情况下,所以让我们一次提供一个完整的类型作为参数,以限制所需的推理数量。

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

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