diff --git a/list/list.go b/list/list.go index a3f0896..a404392 100644 --- a/list/list.go +++ b/list/list.go @@ -5,11 +5,13 @@ import ( "strings" ) + type IList interface { Conj(data any) IList First() any Rest() IList String() string + IsEmpty() bool } type EmptyList struct{} @@ -19,22 +21,21 @@ type List struct { next IList } -func New() IList { +func Empty() IList { return new(EmptyList) } -func single(val any) *List { +var emptyList = Empty() + +func New(val any) *List { this := new(List) this.Value = val - this.next = nil + this.next = emptyList return this } func (this *List) Conj(val any) IList { - if this == nil { - return single(val) - } - new_head := single(val) + new_head := New(val) new_head.next = this return new_head @@ -45,31 +46,29 @@ func (this *EmptyList) Conj(val any) IList { } func Conj(this IList, val any) IList { - var l IList if this == nil { - l = single(val) + return New(val) } else { - l = this + return this.Conj(val) } - return l.Conj(val) } func Rest(this IList) IList { if this == nil { - return nil + return emptyList } return this.Rest() } func (this *List) Rest() IList { if this == nil { - return nil + return emptyList } return this.next } func (this *EmptyList) Rest() IList { - return nil + return emptyList } func First(this *List) any { @@ -84,15 +83,15 @@ func (this *List) First() any { } func (this *EmptyList) First() any { - return First(nil) + return nil } func IsEmpty(this IList) bool { - return this == nil + return this == nil || this.IsEmpty() } func (this *List) IsEmpty() bool { - return this == nil + return false } func (this *EmptyList) IsEmpty() bool { @@ -100,21 +99,17 @@ func (this *EmptyList) IsEmpty() bool { } func String(this *List) string { - if this == nil { + if IsEmpty(this) { return "()" } + var sb strings.Builder sb.WriteRune('(') // Iterate and print elements var e IList - for e = this; e != nil; e = Rest(e) { - switch v := e.(type) { - case *List: - sb.WriteString(fmt.Sprint(v.Value)) - sb.WriteRune(' ') - case *EmptyList: - break - } + for e = this; !IsEmpty(e); e = Rest(e) { + sb.WriteString(fmt.Sprint(e.First())) + sb.WriteRune(' ') } return sb.String()[:sb.Len()-1] + ")" } @@ -124,5 +119,5 @@ func (this *List) String() string { } func (this *EmptyList) String() string { - return String(nil) + return "()" } diff --git a/list/list_test.go b/list/list_test.go index 64f3d4b..93d9d06 100644 --- a/list/list_test.go +++ b/list/list_test.go @@ -5,25 +5,30 @@ import ( "testing" ) +func TestReadString(t *testing.T) { + assert.Equal(t, "()", Empty().String(), "should insert at head") +} + func TestReadConj(t *testing.T) { - l := New().Conj(5).Conj(6).Conj(7) - assert.Equal(t, "(7 6 5)", l.String(), "should insert at head") - l = Conj(New(), 4) - assert.Equal(t, "(4 5)", l.String(), "should insert at head") + var l IList + assert.Equal(t, "()", Empty().String(), "should insert at head") + l = New(5) + 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) { - 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, nil, New().First(), "should return nil") + assert.Equal(t, nil, Empty().First(), "should return nil") } 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, "(5)", l.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, nilPtr, New().Rest(), "should return rest sublist") - assert.Equal(t, nilPtr, Rest(New().Rest()), "should return rest sublist") + assert.Equal(t, Empty(), Empty().Rest(), "should return rest sublist") + assert.Equal(t, Empty(), Rest(Empty().Rest()), "should return rest sublist") } diff --git a/read/read_test.go b/read/read_test.go index 664c9df..16e0b93 100644 --- a/read/read_test.go +++ b/read/read_test.go @@ -43,7 +43,7 @@ func TestReadListElem(t *testing.T) { func TestReadList(t *testing.T) { input := "(1 2 3)" 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, len(input), pos, "should read the whole string") } diff --git a/vector/vector.go b/vector/vector.go index 67bbf23..f20727a 100644 --- a/vector/vector.go +++ b/vector/vector.go @@ -52,7 +52,7 @@ func (this *Vector) String() string { } func ToList(this *Vector) list.IList { - l := list.New() + l := list.Empty() for i := len(this._slice) - 1; i >= 0; i-- { l = list.Conj(l, this._slice[i]) }