start the tower of abstractions
Some checks failed
Go / test (push) Failing after 28s

This commit is contained in:
Adam Jeniski 2025-11-04 12:25:23 -10:00
parent d3997bfb53
commit 4e1cbce3a7
4 changed files with 63 additions and 36 deletions

View File

@ -5,57 +5,71 @@ import (
"strings" "strings"
) )
type IList interface {
Conj(data any) IList
First() any
Rest() IList
String() string
}
type EmptyList struct{} type EmptyList struct{}
type List struct { type List struct {
Value any Value any
next *List next IList
} }
func Empty() *EmptyList { func New() IList {
return new(EmptyList) return new(EmptyList)
} }
func New(val any) *List { func single(val any) *List {
return new(List).Init(val) this := new(List)
}
func (this *List) Init(val any) *List {
return Init(this, val)
}
func Init(this *List, val any) *List {
this.Value = val this.Value = val
this.next = nil this.next = nil
return this return this
} }
func (this *List) Conj(val any) *List { func (this *List) Conj(val any) IList {
return Conj(this, val) 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) return Conj(nil, val)
} }
func Conj(this *List, val any) *List { func Conj(this IList, val any) IList {
var l IList
if this == nil { if this == nil {
return New(val) l = single(val)
} else {
l = this
} }
new_head := New(val) return l.Conj(val)
new_head.next = this
return new_head
} }
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 { if this == nil {
return nil return nil
} }
return this.next return this.next
} }
func (this *List) Rest() *List { func (this *EmptyList) Rest() IList {
return Rest(this) return nil
} }
func First(this *List) any { func First(this *List) any {
@ -73,7 +87,7 @@ func (this *EmptyList) First() any {
return First(nil) return First(nil)
} }
func IsEmpty(this *List) bool { func IsEmpty(this IList) bool {
return this == nil return this == nil
} }
@ -92,9 +106,15 @@ func String(this *List) string {
var sb strings.Builder var sb strings.Builder
sb.WriteRune('(') sb.WriteRune('(')
// Iterate and print elements // Iterate and print elements
for e := this; e != nil; e = Rest(e) { var e IList
sb.WriteString(fmt.Sprint(e.Value)) for e = this; e != nil; e = Rest(e) {
sb.WriteRune(' ') switch v := e.(type) {
case *List:
sb.WriteString(fmt.Sprint(v.Value))
sb.WriteRune(' ')
case *EmptyList:
break
}
} }
return sb.String()[:sb.Len()-1] + ")" return sb.String()[:sb.Len()-1] + ")"
} }
@ -102,3 +122,7 @@ func String(this *List) string {
func (this *List) String() string { func (this *List) String() string {
return String(this) return String(this)
} }
func (this *EmptyList) String() string {
return String(nil)
}

View File

@ -6,20 +6,24 @@ import (
) )
func TestReadConj(t *testing.T) { 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") 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) { 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, 7, l.First(), "should return first element")
assert.Equal(t, nil, Empty().First(), "should return nil") assert.Equal(t, nil, New().First(), "should return nil")
assert.Equal(t, 5, New(5).First(), "should get first from New")
} }
func TestReadRest(t *testing.T) { 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, "(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, nilPtr, New().Rest(), "should return rest sublist")
assert.Equal(t, nilPtr, Rest(New().Rest()), "should return rest sublist")
} }

View File

@ -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(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, 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")
} }

View File

@ -51,15 +51,14 @@ func (this *Vector) String() string {
return String(this) return String(this)
} }
func ToList(this *Vector) *list.List { func ToList(this *Vector) list.IList {
var l *list.List l := list.New()
l = nil
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])
} }
return l return l
} }
func (this *Vector) ToList() *list.List { func (this *Vector) ToList() list.IList {
return ToList(this) return ToList(this)
} }