Strange Scala "Несоответствие типов" для кортежей
У меня есть функция 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) несоответствие типов;
найдено: (Char, Char) => Строка
требуется: ((Char, Char)) => Строка
map[(Char, Char), String](синтаксический анализатор, 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. Не знаю, насколько это актуально.
Ваша помощь ценится.
2 ответа
Тип (Char, Char) => String
соответствует функции, которая принимает два параметра Char и возвращает String.
То, что вы хотите, это функция, которая принимает Tuple2
и возвращает строку, которая как-то отличается.
Его тип должен быть Tuple2[Char, Char] => String
, Tuple2[Char, Char]
соответствует сокращенному типу (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
, Это немного лучше, чем определение функции принятия кортежа, из-за причуд в скобках, с которыми вы столкнулись, а также потому, что вам не нужно деконструировать кортеж в теле.