93 lines
1.9 KiB
Go
93 lines
1.9 KiB
Go
package ps
|
|
|
|
// List is a persistent list of possibly heterogenous values.
|
|
type List interface {
|
|
// IsNil returns true if the list is empty
|
|
IsNil() bool
|
|
|
|
// Cons returns a new list with val as the head
|
|
Cons(val Any) List
|
|
|
|
// Head returns the first element of the list;
|
|
// panics if the list is empty
|
|
Head() Any
|
|
|
|
// Tail returns a list with all elements except the head;
|
|
// panics if the list is empty
|
|
Tail() List
|
|
|
|
// Size returns the list's length. This takes O(1) time.
|
|
Size() int
|
|
|
|
// ForEach executes a callback for each value in the list.
|
|
ForEach(f func(Any))
|
|
|
|
// Reverse returns a list whose elements are in the opposite order as
|
|
// the original list.
|
|
Reverse() List
|
|
}
|
|
|
|
// Immutable (i.e. persistent) list
|
|
type list struct {
|
|
depth int // the number of nodes after, and including, this one
|
|
value Any
|
|
tail *list
|
|
}
|
|
|
|
// An empty list shared by all lists
|
|
var nilList = &list{}
|
|
|
|
// NewList returns a new, empty list. The result is a singly linked
|
|
// list implementation. All lists share an empty tail, so allocating
|
|
// empty lists is efficient in time and memory.
|
|
func NewList() List {
|
|
return nilList
|
|
}
|
|
|
|
func (self *list) IsNil() bool {
|
|
return self == nilList
|
|
}
|
|
|
|
func (self *list) Size() int {
|
|
return self.depth
|
|
}
|
|
|
|
func (tail *list) Cons(val Any) List {
|
|
var xs list
|
|
xs.depth = tail.depth + 1
|
|
xs.value = val
|
|
xs.tail = tail
|
|
return &xs
|
|
}
|
|
|
|
func (self *list) Head() Any {
|
|
if self.IsNil() {
|
|
panic("Called Head() on an empty list")
|
|
}
|
|
|
|
return self.value
|
|
}
|
|
|
|
func (self *list) Tail() List {
|
|
if self.IsNil() {
|
|
panic("Called Tail() on an empty list")
|
|
}
|
|
|
|
return self.tail
|
|
}
|
|
|
|
// ForEach executes a callback for each value in the list
|
|
func (self *list) ForEach(f func(Any)) {
|
|
if self.IsNil() {
|
|
return
|
|
}
|
|
f(self.Head())
|
|
self.Tail().ForEach(f)
|
|
}
|
|
|
|
// Reverse returns a list with elements in opposite order as this list
|
|
func (self *list) Reverse() List {
|
|
reversed := NewList()
|
|
self.ForEach(func(v Any) { reversed = reversed.Cons(v) })
|
|
return reversed
|
|
}
|