Error using repeated parameters

时间:2015-05-24 20:41:00

标签: scala

Despite thinking and reading for several hours I don't understand the error produced by the following code when compiled with version 2.11.6 of the Scala compiler:

object Test
{
  type F = (String) => Set[String]

  def n_ary(f: (F, F) => F) = {
    def n_ary_f(x: F, args: F*): F =
      (t: String) =>
        if (args.isEmpty) x(t)
        else f(x, n_ary_f(args.head, args.tail: _*))(t)

    n_ary_f _
  }

  def seq(x: F, y: F) =
    (t: String) =>
      (for(c <- x(t).toIterator; d <- y(c).toIterator)
        yield d).toSet

  def seq_n(x: F, y: F*): F =
    n_ary(seq)(x, y: _*)
}

The compiler's output is:

params.scala:17: error: type mismatch;
 found   : Seq[Test.F]
    (which expands to)  Seq[String => Set[String]]
 required: Seq[Seq[Test.F]]
    (which expands to)  Seq[Seq[String => Set[String]]]
    n_ary(seq)(x, y: _*)
                  ^

When compiling the code without the _* behind the argument y in the call to n_ary(sec) on the last line there is no error. Nethertheless this seems kind of wrong to me. Version 2.9.2 of the Scala compiler actually produces the following error output when used to compile my code after applying the aforementioned modification to the last line:

params.scala:21: error: type mismatch;
 found   : String => Set[String]*
 required: String => Set[String]
    n_ary(seq)(x, y)
                  ^

In my opinion this error message makes sense, because n_ary's second argument is not a Seq[String => Set[String]], but a String => Set[String], that could also be left out or repeated once or more times. But to avoid this error I would have to undo my change and use the code as listed above leaving me with the aforementioned error when compiled with the current version of scalac ...

Could someone please explain what I am getting wrong here, especially concerning the error produced by the current compiler version?

1 个答案:

答案 0 :(得分:0)

我引入了一个类型别名和附加的函数类型,由Scala推断,以便更清楚地了解您的代码。

  type F = (String) => Set[String]

  def n_ary(f: (F, F) => F): (F, Seq[F]) => F

n_ary会返回类型为(F, Seq[F]) => F的函数,因此y中的n_ary(seq)(x, y)必须包含Seq[F]类型。你可能想要做的是让n_ary返回一个带有重复参数的函数,但即使你将n_ary的返回类型设置为(F, F*) => F它也不起作用。

阅读the spec on function types您意识到所有函数类型都是Function_n[-T1 , … , -Tn, +R]的变体。具有重复参数的函数将具有未知数量的参数类型T,因此无法在Scala的系统中键入。

重复的参数语法似乎是对命名函数的参数列表的一个特殊技巧,它对函数对象不起作用(考虑this this related SO question的接受答案)