Я думаю, что основная причина в том, что одним из наиболее мощных способов использования связанных списков является разделение головы / хвоста. Есть много рекурсивных алгоритмов, которые выглядят так:
def listlen[A](xs: List[A], already: Int = 0): Int = xs match {
case Nil => already
case x :: rest => listlen(rest, already+1)
}
Конечно, списки уже знают, как получить их длину; это всего лишь пример. Дело в том, что вы отрываете голову, а затем делаете что-то еще с хвостом - таким образом работает много полезных вещей.
Поскольку списки неизменны , мы можем сделать что-то еще - мы можем потратить столько времени, сколько мы хотим, чтобы оценить остальную часть нашего списка! Мы не должны закончить за один раз; мы уверены, что это никогда не изменится. Это было бы не так, если бы список был изменчивым - либо нам нужно заблокировать список, чтобы никто другой не видел его, либо нам нужно сделать защитную копию всего этого на случай, если кто-то может поменять его.
Теперь, если вам действительно нужен изменяемый список, есть mutable.LinkedList
, у которого есть хорошие свойства вставки, о которых вы говорите. Но это не дает вам элегантной рекурсии с душевным спокойствием, которую дают вам неизменные списки.
(Обратите внимание, что вы могли бы сделать это с неизменной структурой на основе массива, но возможное преимущество коллекции с каждым обернутым элементом состоит в том, что вам не нужно сохранять или копировать весь массив только потому, что вам нужен несколько элементов с конца; если ранние элементы в списке больше не указаны, они могут быть удалены мусором.)