元组的奇怪 Scala 'Type mismatch' 错误

Strange Scala 'Type mismatch' error for tuples

我有一个函数 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 参数的类型不匹配错误 saying

Error:(26, 41) type mismatch;

found : (Char, Char) => String

required: ((Char, Char)) => String

map[(Char, Char), String](parser, asString)

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

这里的类型 T1 是字符元组 (Char, Char)T2 是一个 String。因此,函数 (Char, Char) => String 应该是输入,但 scala 需要不同的类型。

我在这里错过了什么?为什么它期望 ((Char, Char)) => String 而不是 (Char,Char) => String

我正在使用 Scala 2.12。不知道这是否相关。

感谢您的帮助。

类型 (Char, Char) => String 对应于采用两个 Char 参数和 returns 一个 String 参数的函数。

你想要的是一个函数,它接受一个 Tuple2 和 returns 一个有点不同的字符串。

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

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

正如其他人指出的那样,定义一个接受 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 的等效函数。 这比定义一个获取元组的函数要好一些,因为圆括号会让你 运行 陷入其中,而且,因为你不必在正文中解构元组。