Why are Scala's `Lists` implemented as linked lists

后端 未结 5 1492
闹比i
闹比i 2021-02-19 05:49

I always thought that the benefit of linked lists was that you could add or remove items (especially not from the end) without having to copy lots of elements thanks to the beau

相关标签:
5条回答
  • 2021-02-19 06:27

    Structural sharing. If you perform a higher-order function (map, fold, etc) on the list, you return a new instance of a list that shares the pointers of the previous list.

    Daniel Spiewak did a marvelous presentation about functional data structures at NE Scala last week. See here: http://www.nescala.org/2011/

    0 讨论(0)
  • 2021-02-19 06:28

    However, Scala's List is immutable (at least by default). What is the benefit of having an immutable linked list

    I'm a little late to the party here, but I felt there's an important point no one's made:

    On top of what Rex Kerr said, it's worth pointing out that building a new list by prepending to an immutable singly linked list is a constant time operation. You just create a new node that points to the already existing list. Since the list is immutable you know the new tail won't ever change, and you don't need to copy any data.

    The fact that you can build new, larger, but still immutable lists with a constant time operation, and with a small memory footprint(just the cost of one node) is, I suspect, a large part of the reason the data structure was chosen.

    0 讨论(0)
  • 2021-02-19 06:32

    scala.List is an alias for scala.collection.immutable.List. It is but one of many concrete collection implementations.

    If you're coming from a Java background, equate java.util.List to scala.collection.mutable.Buffer, not to scala.List.

    You can get an overview of the structure of the collections library in the Scala 2.8 Collections Overview.. Here you'll find many other concrete implementations (both mutable and immutable).

    0 讨论(0)
  • 2021-02-19 06:35

    While I have close to no idea how scala is implemented. LinkedLists should be avoided,though.

    They are inefficient on current hardware due to traverse them each Node practically leads to a cache miss. Cache misses are what governs nowadays performance.

    0 讨论(0)
  • 2021-02-19 06:41

    I think the main reason is that one of the most powerful uses of linked lists is head/tail splitting. There are lots of recursive algorithms that look like this one:

    def listlen[A](xs: List[A], already: Int = 0): Int = xs match {
      case Nil => already
      case x :: rest => listlen(rest, already+1)
    }
    

    Of course, lists already know how to get their length; this is just an example. The point is that you pull off the head, and then do something else with the tail--lots of useful things work this way.

    Since lists are immutable, we can do something else--we can take as much time as we want to evaluating the rest of our list! We don't have to finish in one go; we're sure it will never change. This would not be the case if the list were mutable--either we need to lock the list, preventing anyone else from seeing it, or we need to make a defensive copy of the whole thing just in case someone might swap it.

    Now, if you really want a mutable list, there's mutable.LinkedList that has the nice insertion properties that you're talking about. But that doesn't give you the elegant recursion with peace of mind that the immutable lists give you.

    (Note that you could do some of this with an immutable array-backed structure, but the possible benefit of a collection with each element wrapped is that you don't need to save or copy the whole array just because you need a few elements from the end; if the early elements in the list aren't pointed to any more, they can be garbage collected.)

    0 讨论(0)
提交回复
热议问题