diff --git a/list/list.go b/list/list.go index a7956b7..a3f0896 100644 --- a/list/list.go +++ b/list/list.go @@ -5,57 +5,71 @@ import ( "strings" ) +type IList interface { + Conj(data any) IList + First() any + Rest() IList + String() string +} + type EmptyList struct{} type List struct { Value any - next *List + next IList } -func Empty() *EmptyList { +func New() IList { return new(EmptyList) } -func New(val any) *List { - return new(List).Init(val) -} - -func (this *List) Init(val any) *List { - return Init(this, val) -} - -func Init(this *List, val any) *List { +func single(val any) *List { + this := new(List) this.Value = val this.next = nil return this } -func (this *List) Conj(val any) *List { - return Conj(this, val) +func (this *List) Conj(val any) IList { + if this == nil { + return single(val) + } + new_head := single(val) + new_head.next = this + return new_head + } -func (this *EmptyList) Conj(val any) *List { +func (this *EmptyList) Conj(val any) IList { return Conj(nil, val) } -func Conj(this *List, val any) *List { +func Conj(this IList, val any) IList { + var l IList if this == nil { - return New(val) + l = single(val) + } else { + l = this } - new_head := New(val) - new_head.next = this - return new_head + return l.Conj(val) } -func Rest(this *List) *List { +func Rest(this IList) IList { + if this == nil { + return nil + } + return this.Rest() +} + +func (this *List) Rest() IList { if this == nil { return nil } return this.next } -func (this *List) Rest() *List { - return Rest(this) +func (this *EmptyList) Rest() IList { + return nil } func First(this *List) any { @@ -73,7 +87,7 @@ func (this *EmptyList) First() any { return First(nil) } -func IsEmpty(this *List) bool { +func IsEmpty(this IList) bool { return this == nil } @@ -92,9 +106,15 @@ func String(this *List) string { var sb strings.Builder sb.WriteRune('(') // Iterate and print elements - for e := this; e != nil; e = Rest(e) { - sb.WriteString(fmt.Sprint(e.Value)) - sb.WriteRune(' ') + 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 + } } return sb.String()[:sb.Len()-1] + ")" } @@ -102,3 +122,7 @@ func String(this *List) string { func (this *List) String() string { return String(this) } + +func (this *EmptyList) String() string { + return String(nil) +} diff --git a/list/list_test.go b/list/list_test.go index e05765f..64f3d4b 100644 --- a/list/list_test.go +++ b/list/list_test.go @@ -6,20 +6,24 @@ import ( ) func TestReadConj(t *testing.T) { - l := Empty().Conj(5).Conj(6).Conj(7) + 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") } func TestReadFirst(t *testing.T) { - l := Empty().Conj(5).Conj(6).Conj(7) + l := New().Conj(5).Conj(6).Conj(7) assert.Equal(t, 7, l.First(), "should return first element") - assert.Equal(t, nil, Empty().First(), "should return nil") - assert.Equal(t, 5, New(5).First(), "should get first from New") + assert.Equal(t, nil, New().First(), "should return nil") } func TestReadRest(t *testing.T) { - l := Empty().Conj(5).Conj(6).Conj(7) + l := New().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") } diff --git a/read/read_test.go b/read/read_test.go index 9c54b81..664c9df 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(3).Conj(2).Conj(1), l, "should read list") + assert.Equal(t, list.New().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 9ea0499..67bbf23 100644 --- a/vector/vector.go +++ b/vector/vector.go @@ -51,15 +51,14 @@ func (this *Vector) String() string { return String(this) } -func ToList(this *Vector) *list.List { - var l *list.List - l = nil +func ToList(this *Vector) list.IList { + l := list.New() for i := len(this._slice) - 1; i >= 0; i-- { l = list.Conj(l, this._slice[i]) } return l } -func (this *Vector) ToList() *list.List { +func (this *Vector) ToList() list.IList { return ToList(this) }