在Scala中使用“_”而不是显式类型

时间:2014-11-01 18:48:42

标签: scala

我尝试编写以下方法将3个列表连接在一起:

def f[A]: List[A] => List[A] => List[A] => List[A] = _ ++ _ ++ _

但得到了这个编译时错误消息:

<console>:7: error: missing parameter type for expanded function 
   ((x$1, x$2, x$3) => x$1.$plus$plus(x$2).$plus$plus(x$3))
       def f[A]: List[A] => List[A] => List[A] => List[A] = _ ++ _ ++ _

是否可以比以下更简洁地编写它:

scala> def f[A](xs: List[A], ys: List[A], zs: List[A]) = xs ++ ys ++ zs
f: [A](xs: List[A], ys: List[A], zs: List[A])List[A]

2 个答案:

答案 0 :(得分:6)

我至少知道两种方法:

  def f[A]: List[A] => List[A] => List[A] => List[A] =
    a => b => c => a ++ b ++ c

  def f2[A]: (List[A], List[A], List[A]) => List[A] = 
    _ ++ _ ++ _

  val l1 = List(1)
  val l2 = List(2)
  val l3 = List(3)

  println(f(l1)(l2)(l3))
  println(f2(l1, l2, l3))

您的原始_ ++ _ ++ _是具有3个参数的函数的占位符,但您的f是curried函数TypeA =&gt; TypeB =&gt; TypeC =&gt; TypeD(所有类型都等于List)

所以你仍然想使用_ ++ _ ++ _你需要将你的函数转换为3输入函数(或者Tuple3 =&gt;某事物的函数值)

答案 1 :(得分:1)

您遇到的问题是由于可以定义Scala函数的各种方式。首先是&#34;正常&#34;带有(T1, T2, ...) => RetType等签名的非curried函数。

然后有T1 => T2 => ... => RetType形式的curried函数,它本质上是一个高阶1参数函数链,返回其他1参数函数,链的末尾返回实际的返回值。为什么这很有用,请谷歌搜索&#34; scala curried functions&#34;。

表达式_ <someoperator> _ <someoperator> _ ...返回非curried函数,因为它们是Scala中的默认函数。因此,如果您声明foo要返回T1 => T2 => ... => RetType但实际上返回(T1, T2, ...) => RetType,则类型签名将不匹配,scalac会抱怨。

解决方案是使用curried签名和curried函数作为返回值:

def foo1[T]: List[T] => List[T] => List[T] =
  a => b => a ++ b

或使用未经签名的签名和未经证实的返回值:

def foo2[T]: (List[T], List[T]) => List[T] =
  _ ++ _

后者相当于:

def foo2[T]: (List[T], List[T]) => List[T] =
  (a, b) => a ++ b

另一个替代方案是让Scala将未经验证的功能转换为有条件的功能:

def foo2[T]: List[T] => List[T] = (_ ++ _).curried

... ,由于超出此问题范围的原因,类型推断器无法使用,因此您必须注释和首先失去_的简洁性:

def foo2[T]: List[T] => List[T] = ((_: List[T]) ++ (_: List[T])).curried