Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Internal representation of Haskell lists?

Haskell supports some basic operations for recursing through lists, like head, tail, init and last. I'm wondering, internally, how Haskell is representing its list data? If it's a singly-linked list, then init and last operations could become costly as the list grows. If it's a doubly-linked list, all four operations could be made O(1) quite easily, albeit at the expense of some memory. Either way, it's important for me to know, so I can write appropriate code. (although, the ethos of functional programming seems to be one of "ask what it does, not how it does it").

like image 253
limp_chimp Avatar asked Feb 25 '13 08:02

limp_chimp


People also ask

How are lists represented in Haskell?

There are five different ways to construct lists in Haskell: Square-bracket syntax: This is the simplest and most recognisable way. Colon operator: This is very similar to the cons function from Lisp-like languages. It adds a single element to the beginning of a list (and returns a new list).

Can Haskell lists have different types?

Recall earlier that Haskell has many different kinds of types, such as * for value-containing types, [*] for type-level lists, etc. Haskell also has a special kind called Symbol from the module GHC.

How do you check if two lists are equal in Haskell?

If your lists have always same size then just A == B . Also if your lists don't have the same size, just as == bs tells you if they are equal. @Ingo @mort's "working" solution treats, for example, [1,2,3] and [1,2,3,4] as equal, there (==) would not.


1 Answers

Lists are represented as ... singly linked lists. The definition is given by:

data [] a = [] | a : [a]

which you could write as:

data List a = Empty | Cons a (List a)

The memory layout is entirely defined by this.

  • Constructors are heap allocated
  • Internal polymorphic fields are pointers to other allocated nodes
  • The spine is lazy

So you end up with something like this:

enter image description here

So head is O(1) on this structure, while last or (++) is O(n)

There is no magic to data structures in Haskell - their straight-forward definition makes entirely clear what the complexity will be (modulo laziness). If you need different complexity, use a different structure (such as IntMap, Sequence, HashMap, Vector etc)...

like image 98
Don Stewart Avatar answered Dec 16 '22 05:12

Don Stewart