bring back empty() vs new(val)
All checks were successful
Go / test (push) Successful in 10s

This commit is contained in:
Adam Jeniski 2025-11-04 13:03:00 -10:00
parent 4e1cbce3a7
commit db1bd5f322
4 changed files with 39 additions and 39 deletions

View File

@ -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.WriteString(fmt.Sprint(v.Value))
sb.WriteRune(' ') 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 "()"
} }

View File

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

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

View File

@ -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])
} }