This commit is contained in:
parent
4e1cbce3a7
commit
db1bd5f322
49
list/list.go
49
list/list.go
@ -5,11 +5,13 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
type IList interface {
|
type IList interface {
|
||||||
Conj(data any) IList
|
Conj(data any) IList
|
||||||
First() any
|
First() any
|
||||||
Rest() IList
|
Rest() IList
|
||||||
String() string
|
String() string
|
||||||
|
IsEmpty() bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type EmptyList struct{}
|
type EmptyList struct{}
|
||||||
@ -19,22 +21,21 @@ type List struct {
|
|||||||
next IList
|
next IList
|
||||||
}
|
}
|
||||||
|
|
||||||
func New() IList {
|
func Empty() IList {
|
||||||
return new(EmptyList)
|
return new(EmptyList)
|
||||||
}
|
}
|
||||||
|
|
||||||
func single(val any) *List {
|
var emptyList = Empty()
|
||||||
|
|
||||||
|
func New(val any) *List {
|
||||||
this := new(List)
|
this := new(List)
|
||||||
this.Value = val
|
this.Value = val
|
||||||
this.next = nil
|
this.next = emptyList
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *List) Conj(val any) IList {
|
func (this *List) Conj(val any) IList {
|
||||||
if this == nil {
|
new_head := New(val)
|
||||||
return single(val)
|
|
||||||
}
|
|
||||||
new_head := single(val)
|
|
||||||
new_head.next = this
|
new_head.next = this
|
||||||
return new_head
|
return new_head
|
||||||
|
|
||||||
@ -45,31 +46,29 @@ func (this *EmptyList) Conj(val any) IList {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func Conj(this IList, val any) IList {
|
func Conj(this IList, val any) IList {
|
||||||
var l IList
|
|
||||||
if this == nil {
|
if this == nil {
|
||||||
l = single(val)
|
return New(val)
|
||||||
} else {
|
} else {
|
||||||
l = this
|
return this.Conj(val)
|
||||||
}
|
}
|
||||||
return l.Conj(val)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func Rest(this IList) IList {
|
func Rest(this IList) IList {
|
||||||
if this == nil {
|
if this == nil {
|
||||||
return nil
|
return emptyList
|
||||||
}
|
}
|
||||||
return this.Rest()
|
return this.Rest()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *List) Rest() IList {
|
func (this *List) Rest() IList {
|
||||||
if this == nil {
|
if this == nil {
|
||||||
return nil
|
return emptyList
|
||||||
}
|
}
|
||||||
return this.next
|
return this.next
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *EmptyList) Rest() IList {
|
func (this *EmptyList) Rest() IList {
|
||||||
return nil
|
return emptyList
|
||||||
}
|
}
|
||||||
|
|
||||||
func First(this *List) any {
|
func First(this *List) any {
|
||||||
@ -84,15 +83,15 @@ func (this *List) First() any {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (this *EmptyList) First() any {
|
func (this *EmptyList) First() any {
|
||||||
return First(nil)
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func IsEmpty(this IList) bool {
|
func IsEmpty(this IList) bool {
|
||||||
return this == nil
|
return this == nil || this.IsEmpty()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *List) IsEmpty() bool {
|
func (this *List) IsEmpty() bool {
|
||||||
return this == nil
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *EmptyList) IsEmpty() bool {
|
func (this *EmptyList) IsEmpty() bool {
|
||||||
@ -100,21 +99,17 @@ func (this *EmptyList) IsEmpty() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func String(this *List) string {
|
func String(this *List) string {
|
||||||
if this == nil {
|
if IsEmpty(this) {
|
||||||
return "()"
|
return "()"
|
||||||
}
|
}
|
||||||
|
|
||||||
var sb strings.Builder
|
var sb strings.Builder
|
||||||
sb.WriteRune('(')
|
sb.WriteRune('(')
|
||||||
// Iterate and print elements
|
// Iterate and print elements
|
||||||
var e IList
|
var e IList
|
||||||
for e = this; e != nil; e = Rest(e) {
|
for e = this; !IsEmpty(e); e = Rest(e) {
|
||||||
switch v := e.(type) {
|
sb.WriteString(fmt.Sprint(e.First()))
|
||||||
case *List:
|
sb.WriteRune(' ')
|
||||||
sb.WriteString(fmt.Sprint(v.Value))
|
|
||||||
sb.WriteRune(' ')
|
|
||||||
case *EmptyList:
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return sb.String()[:sb.Len()-1] + ")"
|
return sb.String()[:sb.Len()-1] + ")"
|
||||||
}
|
}
|
||||||
@ -124,5 +119,5 @@ func (this *List) String() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (this *EmptyList) String() string {
|
func (this *EmptyList) String() string {
|
||||||
return String(nil)
|
return "()"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,25 +5,30 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func TestReadString(t *testing.T) {
|
||||||
|
assert.Equal(t, "()", Empty().String(), "should insert at head")
|
||||||
|
}
|
||||||
|
|
||||||
func TestReadConj(t *testing.T) {
|
func TestReadConj(t *testing.T) {
|
||||||
l := New().Conj(5).Conj(6).Conj(7)
|
var l IList
|
||||||
assert.Equal(t, "(7 6 5)", l.String(), "should insert at head")
|
assert.Equal(t, "()", Empty().String(), "should insert at head")
|
||||||
l = Conj(New(), 4)
|
l = New(5)
|
||||||
assert.Equal(t, "(4 5)", l.String(), "should insert at head")
|
assert.Equal(t, "(5)", l.String(), "should insert at head")
|
||||||
|
l = Empty().Conj(4)
|
||||||
|
assert.Equal(t, "(4)", l.String(), "should insert at head")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestReadFirst(t *testing.T) {
|
func TestReadFirst(t *testing.T) {
|
||||||
l := New().Conj(5).Conj(6).Conj(7)
|
l := Empty().Conj(5).Conj(6).Conj(7)
|
||||||
assert.Equal(t, 7, l.First(), "should return first element")
|
assert.Equal(t, 7, l.First(), "should return first element")
|
||||||
assert.Equal(t, nil, New().First(), "should return nil")
|
assert.Equal(t, nil, Empty().First(), "should return nil")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestReadRest(t *testing.T) {
|
func TestReadRest(t *testing.T) {
|
||||||
l := New().Conj(5).Conj(6).Conj(7)
|
l := Empty().Conj(5).Conj(6).Conj(7)
|
||||||
assert.Equal(t, "(6 5)", l.Rest().String(), "should return rest sublist")
|
assert.Equal(t, "(6 5)", l.Rest().String(), "should return rest sublist")
|
||||||
assert.Equal(t, "(5)", l.Rest().Rest().String(), "should return rest sublist")
|
assert.Equal(t, "(5)", l.Rest().Rest().String(), "should return rest sublist")
|
||||||
assert.Equal(t, "()", l.Rest().Rest().Rest().String(), "should return rest sublist")
|
assert.Equal(t, "()", l.Rest().Rest().Rest().String(), "should return rest sublist")
|
||||||
var nilPtr *List = nil
|
assert.Equal(t, Empty(), Empty().Rest(), "should return rest sublist")
|
||||||
assert.Equal(t, nilPtr, New().Rest(), "should return rest sublist")
|
assert.Equal(t, Empty(), Rest(Empty().Rest()), "should return rest sublist")
|
||||||
assert.Equal(t, nilPtr, Rest(New().Rest()), "should return rest sublist")
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -43,7 +43,7 @@ func TestReadListElem(t *testing.T) {
|
|||||||
func TestReadList(t *testing.T) {
|
func TestReadList(t *testing.T) {
|
||||||
input := "(1 2 3)"
|
input := "(1 2 3)"
|
||||||
l, err, pos := readList(input, 0, "user")
|
l, err, pos := readList(input, 0, "user")
|
||||||
assert.Equal(t, list.New().Conj(3).Conj(2).Conj(1), l, "should read list")
|
assert.Equal(t, list.Empty().Conj(3).Conj(2).Conj(1), l, "should read list")
|
||||||
assert.Equal(t, nil, err, "should read without error")
|
assert.Equal(t, nil, err, "should read without error")
|
||||||
assert.Equal(t, len(input), pos, "should read the whole string")
|
assert.Equal(t, len(input), pos, "should read the whole string")
|
||||||
}
|
}
|
||||||
|
|||||||
@ -52,7 +52,7 @@ func (this *Vector) String() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func ToList(this *Vector) list.IList {
|
func ToList(this *Vector) list.IList {
|
||||||
l := list.New()
|
l := list.Empty()
|
||||||
for i := len(this._slice) - 1; i >= 0; i-- {
|
for i := len(this._slice) - 1; i >= 0; i-- {
|
||||||
l = list.Conj(l, this._slice[i])
|
l = list.Conj(l, this._slice[i])
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user