Чтобы понять, как это работает, может быть полезно явно распаковать функции, которые вы отправляете, на map
и flatMap
и изучить их подписи. Я переписал их здесь, так что вы можете видеть, что f
- это отображение функции от Int
до кортежа (Int, Int)
, а g
- это функция, которая отображает от Int
до List[Int]
.
val f: (Int) => (Int, Int) = x => (x*2, x*3)
val g: (Int) => List[Int] = x => List(x*2, x*3)
List(1,2,3).map(f)
//res0: List[(Int, Int)] = List((2,3), (4,6), (6,9))
List(1,2,3).map(g)
//res1: List[List[Int]] = List(List(2, 3), List(4, 6), List(6, 9))
//List(1,2,3).flatMap(f) // This won't compile
List(1,2,3).flatMap(g)
//res2: List[Int] = List(2, 3, 4, 6, 6, 9)
Так почему же не будет flatMap(f)
? Давайте посмотрим на подпись для flatMap
, в этом случае вытащил из List
реализации:
final override def flatMap[B, That](f : scala.Function1[A, scala.collection.GenTraversableOnce[B]])(...)
Это немного трудно распаковать, и я некоторые опущены его, но ключ является GenTraversableOnce
типа. List
, если вы следуете его цепочке наследования вверх, имеет это как свойство, с которым оно построено, и, следовательно, функция, которая отображает от какого-то типа A
на List
(или любой объект с признаком GenTraversableOnce
), будет действительной функцией. Примечательно, что кортежи не имеют этой черты.
Это объяснение, связанное с сорняками, почему печатание неверно и стоит объяснить, потому что любая ошибка, которая говорит «не может разрешить ссылку с такой сигнатурой», означает, что она не может найти функцию, которая принимает явные типа, который вы предлагаете. Типы очень часто выводятся в Scala, поэтому вам хорошо известно, что тип, который вы даете, - это тип, ожидаемый методом, который вы вызываете.
Обратите внимание, что flatMap
имеет стандартное значение в функциональном программировании, которое является, грубо говоря, любой функцией отображения, которая потребляет один элемент и производит n элементов, но конечным результатом является объединение всех этих списков.Поэтому функция, которую вы переходите на flatMap
, всегда будет ожидать для создания списка, и функция flatMap
не будет знать, как действовать на отдельные элементы.
Что такое тип ввода? Проверьте подписи 'map' и' flatMap'. У него разные параметры, поэтому ваш код имеет ошибку компиляции. –
Потому что 'flatMap' используется для выравнивания структуры. Когда вы получите 'M [M [A]]' с 'map', вы получите' M [A] 'с' flatMap'. –
Вложенные 'M' иногда могут быть разными,' N' .. Например, 'List [Option [String]]' => 'List [String]' –