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

Lui*_*hys 5 scala type-inference anonymous-function enrich-my-library

假设我有一个方法将(两个元素上的函数)转换为(两个序列上的函数):

def seqed[T](f: (T,T) => T): (Seq[T], Seq[T]) => Seq[T] = (_,_).zipped map f
Run Code Online (Sandbox Code Playgroud)

在的话,所得到的函数有两个序列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)
Run Code Online (Sandbox Code Playgroud)

或者使用匿名函数:

xss reduceLeft seqed[Int](_+_)
Run Code Online (Sandbox Code Playgroud)

这很不错; 摆脱[Int]类型参数会很好,但我不知道(任何想法?).

为了让它感觉更像这个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)
Run Code Online (Sandbox Code Playgroud)

对于预定义的功能,这很有用,但是对于匿名的功能来说很难看

xss reduceLeft f.seqed
xss reduceLeft ((_:Int) + (_:Int)).seqed
Run Code Online (Sandbox Code Playgroud)

有没有其他方法我可以重新构造这样的类型被推断,我可以使用语法如下:

// pseudocode
xss reduceLeft (_+_).seqed         // ... or failing that
xss reduceLeft (_+_).seqed[Int]
Run Code Online (Sandbox Code Playgroud)

?或者我是否要求过多的类型推断?

Dan*_*ral 5

你不能按照你想要的方式去做,但是看看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)
Run Code Online (Sandbox Code Playgroud)


Lui*_*hys 0

需要类型注释的原因

\n\n
xss reduceLeft seqed[Int](_+_)\n
Run Code Online (Sandbox Code Playgroud)\n\n

但不在

\n\n
xs zip ys map Function.tupled(_+_)\n
Run Code Online (Sandbox Code Playgroud)\n\n

map是由于和之间的类型要求不同造成的reduceLeft

\n\n
def reduceLeft [B >: A] (f: (B, A) \xe2\x87\x92 B): B \ndef map        [B]      (f: (A) \xe2\x87\x92 B): Seq[B]   // simple version!\n
Run Code Online (Sandbox Code Playgroud)\n\n

reduceLeft期望seqed返回类型Bwhere B >: Int。因此似乎seqed无法知道 for 的精确类型,因此我们必须提供注释。此问题中的更多信息。

\n\n

reduceLeft克服这个问题的一种方法是在没有下限的情况下重新实现。

\n\n
implicit def withReduceL[T](xs: Seq[T]) = new {\n  def reduceL(f: (T, T) => T) = xs reduceLeft f\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

测试:

\n\n
scala> Seq(Seq(1,2,3), Seq(2,2,2)) reduceL seqed(_+_)\nres1: Seq[Int] = List(3, 4, 5)\n
Run Code Online (Sandbox Code Playgroud)\n\n

现在的问题是,这不适用于Seq(eg List) 的子类型,无论是否带有[Int]参数:

\n\n
scala> Seq(List(1,2,3), List(2,2,2)) reduceL seqed(_+_)\n<console>:11: error: missing parameter type for expanded function ((x$1, x$2) => x$1.$plus(x$2))\n              Seq(List(1,2,3), List(2,2,2)) reduceL seqed(_+_)\n                                                          ^\n
Run Code Online (Sandbox Code Playgroud)\n\n

reduceL需要类型为 的函数(List[Int], List[Int]) => List[Int]。因为Function2定义为Function2 [-T1, -T2, +R](Seq[Int], Seq[Int]) => Seq[Int]不是有效的替换。

\n