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, Это немного лучше, чем определение функции принятия кортежа, из-за причуд в скобках, с которыми вы столкнулись, а также потому, что вам не нужно деконструировать кортеж в теле.

Другие вопросы по тегам