4 Random Access Lists
Following Random Access List structures implement and provide the functions list, empty?, cons, head, tail, list-ref, list-set, drop, list-length and ->list. The implementations of the two data structures are based on numerical representations. Binary random access lists uses the binary number representation and running time of its basic list and random access operations, in worst-case, is logarithmic. Where as skew binary random access lists use skew binary number representation and running time of its basic operations is constant in worst-case. And both the implementations are polymorphic. And our benchmarks indicate that the operations of skew binary random access lists are faster.
4.1 Binary Random Access List
(require pfds/ralist/binary) | package: pfds |
Random Access Lists are list data structures that provide array-like lookup and update operations. They have been implemented as a framework of binary numerical representation using complete binary leaf trees. It has a worst case running time of O(log(n)) for the operations cons, first, rest, list-ref and list-set.
syntax
(List A)
> (list 1 2 3 4 5 6) - : (U (List Nothing) (Root Positive-Byte))
#<Root>
In the above example, (list 1 2 3 4 5 6) gives a Binary Random Access List which is similar to lists but comes with efficient list-ref and list-set operations.
In the above example, (cons 10 (list 5 3 5 6)) returns (list 10 5 3 5 6).
In the above example, (rest ral) returns the rest of the given list, (list 2 3 4 5 6).
> (list-ref (list 12 5 3 2 15 23) 4) - : Integer [more precisely: Positive-Byte]
15
> (list-ref (list 12 5 3 2 15 23) 10) list-ref: given index out of bound
> (list-set (list 1 2 3 4 5 6) 2 10) - : (U (List Nothing) (Root Positive-Byte))
#<Root>
> (list-set (list 1 2 3 4 5 6) 10 15) list-set: given index out of bound
In the above example, (list-set (list 1 2 3 4 5 6) 2 10) returns (list 1 2 10 4 5 6) and (list-set (list 1 2 3 4 5 6) 10 15) throws an error.
In the above example, (->list ral) returns (list 1 2 3 4 5 6).
> (drop 3 (list 1 2 3 4 5 6)) - : (U (List Nothing) (Root Positive-Byte))
#<Root>
> (drop 10 (list 1 2 3 4 5 6)) drop: not enough elements to drop
In the above example, (drop 3 (list 1 2 3 4 5 6)) returns the list (list 4 5 6). (drop 10 (list 1 2 3 4 5 6)) throws an error since 10 is larger than the number of elements in the list.
In the above example, (map add1 (list 1 2 3 4 5 6)) adds 1 to each element of the given list and returns (list 2 3 4 5 6 7). (map * (list 1 2 3 4 5 6) (list 1 2 3 4 5 6)) multiplies corresponding elements in the two lists and returns the list (list 1 4 9 16 25 36).
procedure
(foldl func init lst1 lst2 ...) → C
func : (C A B ... B -> C) init : C lst1 : (List A) lst2 : (List B)
foldl currently does not produce correct results when the given function is non-commutative.
> (foldl + 0 (list 1 2 3 4 5 6)) - : Integer [more precisely: Nonnegative-Integer]
21
> (foldl * 1 (list 1 2 3 4 5 6) (list 1 2 3 4 5 6)) - : Integer [more precisely: Positive-Integer]
518400
procedure
(foldr func init lst1 lst2 ...) → C
func : (C A B ... B -> C) init : C lst1 : (List A) lst2 : (List B)
foldr currently does not produce correct results when the given function is non-commutative.
> (foldr + 0 (list 1 2 3 4 5 6)) - : Integer [more precisely: Nonnegative-Integer]
21
> (foldr * 1 (list 1 2 3 4 5 6) (list 1 2 3 4 5 6)) - : Integer [more precisely: Positive-Integer]
518400
procedure
(andmap func lst1 lst2 ...) → Boolean
func : (A B ... B -> Boolean) lst1 : (List A) lst2 : (List B)
> (andmap even? (list 1 2 3 4 5 6)) - : Boolean
#f
> (andmap odd? (list 1 2 3 4 5 6)) - : Boolean
#f
> (andmap positive? (list 1 2 3 4 5 6)) - : Boolean
#t
> (andmap negative? (list -1 -2)) - : Boolean
#t
procedure
(ormap func lst1 lst2 ...) → Boolean
func : (A B ... B -> Boolean) lst1 : (List A) lst2 : (List B)
> (ormap even? (list 1 2 3 4 5 6)) - : Boolean
#t
> (ormap odd? (list 1 2 3 4 5 6)) - : Boolean
#t
> (ormap positive? (list -1 -2 3 4 -5 6)) - : Boolean
#t
> (ormap negative? (list 1 -2)) - : Boolean
#t
procedure
(build-list size func) → (List A)
size : Natural func : (Natural -> A)
> (->list (build-list 5 (λ:([x : Integer]) (add1 x)))) - : (Listof Integer)
'(1 2 3 4 5)
> (->list (build-list 5 (λ:([x : Integer]) (* x x)))) - : (Listof Integer)
'(0 1 4 9 16)
> (->list (remove (λ:([x : Integer]) (> x 5)) (list 1 2 3 4 5 6))) - : (Listof Positive-Byte)
'(1 2 3 4 5)
> (->list (remove (λ:([x : Integer]) (< x 5)) (list 1 2 3 4 5 6))) - : (Listof Positive-Byte)
'(5 6)
> (->list (remove (λ:([x : Integer]) (<= x 4)) (list 1 2 3 4 5 6))) - : (Listof Positive-Byte)
'(5 6)
> (last (list 1 2 3 4 5 6 7 8 9 10 11)) - : Integer [more precisely: Positive-Byte]
11
> (last (list 1 2 3 4 5)) - : Integer [more precisely: Positive-Byte]
5
4.2 Skew Binary Random Access List
(require pfds/ralist/skew) | package: pfds |
Random Access Lists are list data structures that provide array-like lookup and update operations. Skew Binary Random Access Lists are implemented using skew binary numbers. It provides a worst case running time of O(1) for the operations cons, first and rest and O(log(n)) for the operations list-ref and list-set.
syntax
(List A)
> (list 1 2 3 4 5 6) - : (Listof (Pairof Integer (U (Leaf Positive-Byte) (Node Positive-Byte))))
(list (cons 3 (Node 1 (Leaf 2) (Leaf 3))) (cons 3 (Node 4 (Leaf 5) (Leaf 6))))
In the above example, (list 1 2 3 4 5 6) gives a Skew Binary Random Access List which is similar to lists and has efficient lookup and update operations.
In the above example, (cons 10 (list 1 2 3 4 5 6)) returns a (list 10 1 2 3 4 5 6).
In the above example, (rest (list 1 2 3 4 5 6)) returns the (list 2 3 4 5 6).
> (list-ref (list 1 2 3 4 5 6) 0) - : Integer [more precisely: Positive-Byte]
1
> (list-ref (list 1 2 3 4 5 6) 3) - : Integer [more precisely: Positive-Byte]
4
> (list-ref (list 1 2 3 4 5 6) 10) list-ref: given index out of bounds
> (->list (list-set (list 1 2 3 4 5 6) 3 10)) - : (Listof Positive-Byte)
'(1 2 3 10 5 6)
> (->list (list-set (list 1 2 3 4 5 6) 6 10)) list-set: given index out of bounds
In the above example, (list-set (list 1 2 3 4 5 6) 3 10) returns (list 1 2 3 10 5 6), (list-set (list 1 2 3 4 5 6) 6 10) throws an error since there are only six elements in the list and it is trying to update seventh element.
> (drop 3 (list 1 2 3 4 5 6)) - : (Listof (Pairof Integer (U (Leaf Positive-Byte) (Node Positive-Byte))))
(list (cons 3 (Node 4 (Leaf 5) (Leaf 6))))
> (drop 0 (list 1 2 3 4 5 6)) - : (Listof (Pairof Integer (U (Leaf Positive-Byte) (Node Positive-Byte))))
(list (cons 3 (Node 1 (Leaf 2) (Leaf 3))) (cons 3 (Node 4 (Leaf 5) (Leaf 6))))
> (drop 10 (list 1 2 3 4 5 6)) drop: not enough elements to drop
In the above example, (drop 3 (list 1 2 3 4 5 6) 3) returns (list 4 5 6). (drop 0 (list 1 2 3 4 5 6)) returns the (list 1 2 3 4 5 6). If the given n is larger than the number of elements in the list, then it throws an error.
> (length (list 1 2 3 4 5 6)) - : Integer
6
> (length (list 1 2 3)) - : Integer
3
> (length empty) - : Integer
0
map currently works on only upto 3 lists because of some issues with contracts.
In the above example, (map add1 (list 1 2 3 4 5 6)) adds 1 to each element of the given list and returns (list 2 3 4 5 6 7). (map * (list 1 2 3 4 5 6) (list 1 2 3 4 5 6)) multiplies corresponding elements in the two lists and returns the list (list 1 4 9 16 25 36).
procedure
(foldl func init lst1 lst2 ...) → C
func : (C A B ... B -> C) init : C lst1 : (List A) lst2 : (List B)
foldl currently does not produce correct results when the given function is non-commutative.
> (foldl + 0 (list 1 2 3 4 5 6)) - : Integer [more precisely: Nonnegative-Integer]
21
> (foldl * 1 (list 1 2 3 4 5 6) (list 1 2 3 4 5 6)) - : Integer [more precisely: Positive-Integer]
518400
procedure
(foldr func init lst1 lst2 ...) → C
func : (C A B ... B -> C) init : C lst1 : (List A) lst2 : (List B)
foldr currently does not produce correct results when the given function is non-commutative.
> (foldr + 0 (list 1 2 3 4 5 6)) - : Integer [more precisely: Nonnegative-Integer]
21
> (foldr * 1 (list 1 2 3 4 5 6) (list 1 2 3 4 5 6)) - : Integer [more precisely: Positive-Integer]
518400
procedure
(andmap func lst1 lst2 ...) → Boolean
func : (A B ... B -> Boolean) lst1 : (List A) lst2 : (List B)
> (andmap even? (list 1 2 3 4 5 6)) - : Boolean
#f
> (andmap odd? (list 1 2 3 4 5 6)) - : Boolean
#f
> (andmap positive? (list 1 2 3 4 5 6)) - : Boolean
#t
> (andmap negative? (list -1 -2)) - : Boolean
#t
procedure
(ormap func lst1 lst2 ...) → Boolean
func : (A B ... B -> Boolean) lst1 : (List A) lst2 : (List B)
> (ormap even? (list 1 2 3 4 5 6)) - : Boolean
#t
> (ormap odd? (list 1 2 3 4 5 6)) - : Boolean
#t
> (ormap positive? (list -1 -2 3 4 -5 6)) - : Boolean
#t
> (ormap negative? (list 1 -2)) - : Boolean
#t
procedure
(build-list size func) → (List A)
size : Natural func : (Natural -> A)
> (->list (build-list 5 (λ:([x : Integer]) (add1 x)))) - : (Listof Integer)
'(1 2 3 4 5)
> (->list (build-list 5 (λ:([x : Integer]) (* x x)))) - : (Listof Integer)
'(0 1 4 9 16)
> (->list (remove (λ:([x : Integer]) (> x 5)) (list 1 2 3 4 5 6))) - : (Listof Positive-Byte)
'(1 2 3 4 5)
> (->list (remove (λ:([x : Integer]) (< x 5)) (list 1 2 3 4 5 6))) - : (Listof Positive-Byte)
'(5 6)
> (->list (remove (λ:([x : Integer]) (<= x 4)) (list 1 2 3 4 5 6))) - : (Listof Positive-Byte)
'(5 6)