Scala: определение функции как правильного типа - PullRequest
4 голосов
/ 15 ноября 2011

Я играл с кодом Scala и столкнулся с ошибкой компилятора, которую я не понимаю. Код генерирует вектор пар Ints, а затем пытается его отфильтровать.

val L = for (x <- (1 to 5)) yield (x, x * x) 
val f = (x: Int, y: Int) => x > 3
println(L.filter(f))

Компилятор жалуется на попытку использовать f в качестве аргумента для метода filter с сообщением об ошибке компилятора:

error: type mismatch;
found   : (Int, Int) => Boolean
required: ((Int, Int)) => Boolean

Как правильно определить функцию f для соответствия требуемому типу функции? Я пытался добавить дополнительные скобки вокруг (x: Int, y: Int), но это дало:

error: not a legal formal parameter
   val f = ((x: Int, y: Int)) => x > 3
            ^

Ответы [ 3 ]

13 голосов
/ 15 ноября 2011

f имеет тип Function2[Int, Int, Boolean].Тип L равен IndexedSeq[Tuple2[Int, Int]], поэтому filter ожидает функцию типа Function1[Tuple2[Int, Int], Boolean].Каждая черта FunctionN[A, B, .., R] имеет метод tupled, который возвращает функцию типа Function1[TupleN[A, B, ..], R].Вы можете использовать его здесь для преобразования f в тип, ожидаемый L.filter.

println(L.filter(f.tupled))
> Vector((4,16), (5,25))

В качестве альтернативы вы можете переопределить f, чтобы он был Function1[Tuple2[Int, Int], Boolean], как указано ниже, и использовать его напрямую.*

val f = (t: (Int, Int)) => t._1 > 3
println(L.filter(f))
> Vector((4,16), (5,25))
6 голосов
/ 15 ноября 2011
val f = (xy: (Int, Int)) => xy._1 > 3
println (L.filter (f))

Если вы делаете

val f = (x: Int, y: Int) => x > 3

вы определяете функцию, которая принимает два целых числа, что отличается от функции, которая принимает пару значений в качестве параметра.

Сравните:

scala> val f = (x: Int, y: Int) => x > 3
f: (Int, Int) => Boolean = <function2>

scala> val f = (xy: (Int, Int)) => xy._1 > 3
f: ((Int, Int)) => Boolean = <function1>
0 голосов
/ 05 мая 2013

Если вы не хотите переписывать свою функцию для явного использования Tuple2 (как предложено пропущенным фактором и неизвестным пользователем), вы можете определить неявный метод, который сделает это автоматически. Это позволяет функции нетронутой (вы не обязаны всегда вызывать ее с параметром Tuple2) и легче для понимания, потому что вы все еще используете идентификаторы x и y.

implicit def fun2ToTuple[A,B,Res](f:(A,B)=>Res):((A,B))=>Res = 
  (t:(A,B)) => f(t._1, t._2)
val L = for (x <- (1 to 5)) yield (x, x * x)
val f = (x: Int, y: Int) => x > 3
val g = (x: Int, y: Int) => x % 2 > y % 3
L.filter(f)    //> Vector((4,16), (5,25))
L.filter(g)    //> Vector((3,9))
f(0,1)         //> false
f((4,2))       //> true

Теперь каждая Function2 также может использоваться как Function1 с Tuple2 в качестве параметра, поскольку она использует неявный метод для преобразования функции при необходимости.

Для функций с более чем двумя параметрами неявное определение выглядит примерно так:

implicit def fun3ToTuple[A,B,C,Res](f:(A,B,C)=>Res):((A,B,C))=>Res = 
  (t:(A,B,C)) => f(t._1, t._2, t._3)
implicit def fun4ToTuple[A,B,C,D,Res](f:(A,B,C,D)=>Res):((A,B,C,D))=>Res = 
  (t:(A,B,C,D)) => f(t._1, t._2, t._3, t._4)
...
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...