Почему передача Nil в foldLeft не работает?

Когда я создаю список, используя foldLeft, меня часто раздражает необходимость явного ввода введенного параметра, и я хотел бы просто использовать ` Ноль вместо этого - вот надуманный пример:

scala> List(1,2,3).foldLeft(List[Int]())((x,y) =>  y :: x)
res17: List[Int] = List(3, 2, 1)

scala> List(1,2,3).foldLeft(Nil)((x, y) => y :: x)
<console>:10: error: type mismatch;
 found   : List[Int]
 required: scala.collection.immutable.Nil.type
              List(1,2,3).foldLeft(Nil)((x,y) =>  y :: x)

Это не так уж плохо с List[Int], но как только вы начнете использовать списки ваших собственных классов, которые почти наверняка будет иметь более длинные имена или даже списки кортежей или других контейнеров, так что вам нужно указать несколько имен классов, это будет ужасно:

list.foldLeft(List.empty[(SomethingClass, SomethingElseClass)]) { (x,y) => y :: x }

Я предполагаю, что причина этого не в том, что с чем-то вроде 5 :: Nil компилятор может определить тип пустой список должен быть List[Int], но когда Nil передается в качестве параметра foldLeft, ему не хватает информации для этого, и к тому времени, когда он возвращается к используется его тип установлен. Но правда ли, что не смог? Может ли он не выводить тип из возвращаемого типа функции, передаваемой в качестве второго аргумента?

А если нет, есть ли какая-то аккуратная идиома, о которой я просто не знаю?

14 голосов | спросил Russell 20 MarpmTue, 20 Mar 2012 15:12:19 +04002012-03-20T15:12:19+04:0003 2012, 15:12:19

2 ответа


0

Механизм логического вывода типа Scalas работает слева направо, поэтому scalac не может вывести правильный тип для первого списка параметров foldLeft. Вы должны дать компилятору подсказку, какой тип использовать. Вместо использования List[TYPE]() вы можете использовать List.empty[TYPE]

(List(1,2,3) foldLeft List.empty[Int]) { (x,y) =>  y :: x }
(List.empty[Int] /: List(1, 2, 3)) { (x,y) => y :: x }
ответил kiritsuku 20 MarpmTue, 20 Mar 2012 15:22:38 +04002012-03-20T15:22:38+04:0003 2012, 15:22:38
0

Вывод типа Scala работает по одному блоку параметров за раз. Nil без какого-либо другого контекста не имеет определенного типа, поэтому возможен наиболее ограничительный тип (Nothing) выбрано.

Он также не может определить тип возвращаемого значения функции, поскольку тип возвращаемого значения зависит от типа Nil. В общем, выбраться из такого рода цикличности довольно сложно (если вы не укажете, что имеете в виду).

Есть несколько приемов, которые можно применить, чтобы сделать вещи менее громоздкими.

Во-первых, сигнатура типа fold имеет только тип коллекции, поэтому, если вы можете использовать этот вид сгиба, вы можно обойти проблему. Например, вы можете написать свой собственный реверс-сглаживание:

List(List(1),List(2),List(3)).fold(Nil)( (x,y) => y ::: x )

Во-вторых, если вы создаете новую коллекцию того же типа, часто проще использовать существующую коллекцию для создания пустой, чем пытаться подключать типы для пустой коллекции. Это особенно легко, если у вас где-то определен канал:

class PipeAnything[A](a: A) { def |>[B](f: A => B) = f(a) }
implicit def anything_can_be_piped[A](a: A) = new PipeAnything(a)

List(1,2,3) |> { x => x.foldLeft(x.take(0))( (y,z) => z :: y ) }

Наконец, не забывайте, что вы можете довольно легко определить свои собственные методы, которые могут сделать что-то в соответствии с вашими типами, даже если вам придется использовать немного хитрости, чтобы заставить его работать:

def foldMe[A,B](example: A, list: List[B])(f: (List[A],B) => List[A]) = {
  (List(example).take(0) /: list)(f)
}

scala> foldMe( ("",0), List("fish","wish","dish") )( (x,y) => (y.take(1), y.length) :: x )
res40: List[(java.lang.String, Int)] = List((d,4), (w,4), (f,4))

Здесь обратите внимание, что пример не ноль , а скорее используется только в качестве примера того, что вам нужно, с нужным вам типом.

ответил Rex Kerr 20 MarpmTue, 20 Mar 2012 15:52:10 +04002012-03-20T15:52:10+04:0003 2012, 15:52:10

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132