[英]Type inference on anonymous functions with enrich-my-library
Say I have a method that turns a (function on two elements) into a (function on two sequences): 假设我有一个方法将(两个元素上的函数)转换为(两个序列上的函数):
def seqed[T](f: (T,T) => T): (Seq[T], Seq[T]) => Seq[T] = (_,_).zipped map f
In words, the resulting function takes two sequences xs
and ys
, and creates a new sequence consisting of (xs(0) f ys(0), xs(1) f ys(1), ...)
So, for example, if xss
is Seq(Seq(1,2),Seq(3,4))
and f
is (a: Int, b: Int) => a + b
, we can invoke it thus: 换句话说,结果函数采用两个序列
xs
和ys
,并创建一个由(xs(0) f ys(0), xs(1) f ys(1), ...)
组成的新序列。例如,如果xss
是Seq(Seq(1,2),Seq(3,4))
并且f
是(a: Int, b: Int) => a + b
,我们可以调用它:
xss reduceLeft seqed(f) // Seq(4, 6)
or with an anonymous function: 或者使用匿名函数:
xss reduceLeft seqed[Int](_+_)
This is pretty good; 这很不错; it would be nice to get rid of the
[Int]
type argument but I don't see how (any ideas?). 摆脱
[Int]
类型参数会很好,但我不知道(任何想法?)。
To make it feel a bit more like the tupled
method, I also tried the enrich-my-library pattern: 为了让它感觉更像是
tupled
方法,我还尝试了rich-my-library模式:
class SeqFunction[T](f: (T,T) => T) {
def seqed: (Seq[T], Seq[T]) => Seq[T] = (_,_).zipped map f
}
implicit def seqFunction[T](f: (T,T) => T) = new SeqFunction(f)
For a pre-defined function this works great, but it's ugly with anonymous ones 对于预定义的功能,这很有用,但是对于匿名的功能来说很难看
xss reduceLeft f.seqed
xss reduceLeft ((_:Int) + (_:Int)).seqed
Is there another way I can reformulate this so that the types are inferred, and I can use syntax something like: 有没有其他方法我可以重新构造这样的类型被推断,我可以使用语法如下:
// pseudocode
xss reduceLeft (_+_).seqed // ... or failing that
xss reduceLeft (_+_).seqed[Int]
? ? Or am I asking too much of type inference?
或者我是否要求过多的类型推断?
You can't do it the way you want, but look at Function.tupled
, which is a counter-part to .tupled
that solves this very same problem. 你不能按照你想要的方式去做,但是看看
Function.tupled
,它是.tupled
一个对应部分,可以解决这个问题。
scala> List(1, 2, 3) zip List(1, 2, 3) map (_ + _).tupled
<console>:8: error: missing parameter type for expanded function ((x$1, x$2) => x$1.$plus(x$2))
List(1, 2, 3) zip List(1, 2, 3) map (_ + _).tupled
^
<console>:8: error: missing parameter type for expanded function ((x$1: <error>, x$2) => x$1.$plus(x$2))
List(1, 2, 3) zip List(1, 2, 3) map (_ + _).tupled
^
scala> List(1, 2, 3) zip List(1, 2, 3) map Function.tupled(_ + _)
res7: List[Int] = List(2, 4, 6)
I am pretty sure you are asking too much. 我敢肯定你是问太多。 Type inference in Scala goes from left to right , so the type of
(_+_)
needs to be figured out first before even considering the .sedeq
part. Scala中的类型推断从左到右 ,因此在考虑
.sedeq
部分之前,需要首先计算(_+_)
的类型。 And there isn't enough information there. 那里没有足够的信息。
The reason why a type annotation is required in 之所以需要类型注释
xss reduceLeft seqed[Int](_+_)
but not in 但不是
xs zip ys map Function.tupled(_+_)
is due to the difference in type requirements between map
and reduceLeft
. 是由于
map
和reduceLeft
之间的类型要求不同。
def reduceLeft [B >: A] (f: (B, A) ⇒ B): B
def map [B] (f: (A) ⇒ B): Seq[B] // simple version!
reduceLeft
expects seqed
to return type B
where B >: Int
. reduceLeft
期望seqed
返回类型B
,其中B >: Int
。 It seems that therefore the precise type for seqed
cannot be known, so we have to provide the annotation. 因此似乎无法知道
seqed
的精确类型,因此我们必须提供注释。 More info in this question . 这个问题的更多信息。
One way to overcome this is to re-implement reduceLeft
without the lower bound. 解决此问题的一种方法是在没有下限的情况下重新实现
reduceLeft
。
implicit def withReduceL[T](xs: Seq[T]) = new {
def reduceL(f: (T, T) => T) = xs reduceLeft f
}
Test: 测试:
scala> Seq(Seq(1,2,3), Seq(2,2,2)) reduceL seqed(_+_)
res1: Seq[Int] = List(3, 4, 5)
The problem now is that this now doesn't work on subtypes of Seq
(eg List
), with or without the [Int]
parameter: 现在的问题是,现在这对
Seq
子类型(例如List
)不起作用,有或没有[Int]
参数:
scala> Seq(List(1,2,3), List(2,2,2)) reduceL seqed(_+_)
<console>:11: error: missing parameter type for expanded function ((x$1, x$2) => x$1.$plus(x$2))
Seq(List(1,2,3), List(2,2,2)) reduceL seqed(_+_)
^
reduceL
expects a function of type (List[Int], List[Int]) => List[Int]
. reduceL
期望类型的函数(List[Int], List[Int]) => List[Int]
。 Because Function2
is defined as Function2 [-T1, -T2, +R]
, (Seq[Int], Seq[Int]) => Seq[Int]
is not a valid substitution. 因为
Function2
被定义为Function2 [-T1, -T2, +R]
, (Seq[Int], Seq[Int]) => Seq[Int]
不是有效替换。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.