元组的奇怪Scala“类型不匹配”错误

时间:2018-07-20 07:00:46

标签: scala generics types tuples scala-generics

我有一个map的函数Parser和一个定义如下的函数:

def map[T1, T2](parser: Parser[T1], func: T1 => T2): Parser[T2]

我创建了一个Parser类型的[(Char, Char)]对象和一个函数(Char, Char) => String

val parser[(Char,Char)] = //...
val asString: (Char, Char) => String = (a: Char, b: Char) => a.toString + b.toString

然后将这两个参数传递给map函数。

val mParser: Parser[String] = map(parser, asString)

我希望一切正常,但是我收到asString参数说的类型不匹配错误

  

错误:(26,41)类型不匹配;

     

found:(Char,Char)=>字符串

     

必填:((Char,Char))=>字符串

     

map [(Char,Char),String](解析器,asString)

我尝试将map的类型显式指定为map[(Char, Char), String](parser, asString),但这也无济于事。

这里的类型T1是字符元组(Char, Char),而T2String。因此,功能(Char, Char) => String应该是输入,但是scala期望使用其他类型。

我在这里想念什么?为什么会期望((Char, Char)) => String而不是(Char,Char) => String

我正在使用Scala 2.12。不知道这是否有任何意义。

感谢您的帮助。

2 个答案:

答案 0 :(得分:2)

类型(Char, Char) => String对应于一个带有两个Char参数并返回String的函数。

您想要的是一个函数,该函数需要一个Tuple2并返回一个有所不同的String。

其类型应为Tuple2[Char, Char] => StringTuple2[Char, Char]对应于类型简写(Char, Char),但是我猜想在函数定义期间,编译器将括号解释为好像它们用于对函数参数进行分组一样。

这是一个已知问题,已在scala3中解决。 https://dotty.epfl.ch/docs/reference/auto-parameter-tupling.html

答案 1 :(得分:1)

正如其他人指出的那样,定义一个接受Tuple2而不是两个参数的函数会有些棘手,看起来也很丑陋。

一种不错的解决方法是使用.tupled

 val asString: (Char, Char) => String = (a: Char, b: Char) => a.toString + b.toString
 val mParser: Parser[String] = map(parser, asString.tupled)

FunctionN.tupled将接受N个参数的函数转换为带有TupleN的等效参数。 这比定义元组获取函数要好一些,这是因为您遇到了括号中的怪癖,而且还因为您不必在体内分解元组。