简体   繁体   English

使用enrich-my-library键入匿名函数的推断

[英]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: 换句话说,结果函数采用两个序列xsys ,并创建一个由(xs(0) f ys(0), xs(1) f ys(1), ...)组成的新序列。例如,如果xssSeq(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 . 是由于mapreduceLeft之间的类型要求不同。

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.

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