From 141f8d3e671f8131ad37798553071cd00c71b5d4 Mon Sep 17 00:00:00 2001 From: Jordan Orelli Date: Thu, 25 Nov 2021 00:34:51 -0600 Subject: [PATCH] map iterator i guess --- iter/iter.go | 30 ++++++++++++++++--------- iter/slice.go | 27 ++++++++++++++++++---- iter/slice_test.go | 19 ++++++++++++++++ list/iter.go | 56 ---------------------------------------------- 4 files changed, 62 insertions(+), 70 deletions(-) create mode 100644 iter/slice_test.go delete mode 100644 list/iter.go diff --git a/iter/iter.go b/iter/iter.go index e026245..203c139 100644 --- a/iter/iter.go +++ b/iter/iter.go @@ -81,23 +81,33 @@ func Max[T constraints.Ordered](src Able[T]) T { return max } +type mapIter[T, Z any] struct { + fn func(T) Z + src Ator[T] +} + +func (it mapIter[T, Z]) Next(v *Z) bool { + var t T + if !it.src.Next(&t) { + return false + } + *v = it.fn(t) + return true +} + +func (it mapIter[T, Z]) Iter() Ator[Z] { return it } + +func Map[T, Z any](src Able[T], f func(T) Z) Able[Z] { + return mapIter[T, Z]{fn: f, src: src.Iter()} +} + // Discarded Iterator types: // -// This was my first attempt. I like to have a method that returns a bool so -// you can use it succinctly in a for loop, but I didn't love having to call -// both done and next -// // type Ator[T any] interface { // Done() bool // Next() T // } // -// I was never optimistic about this. In practice, using this in a for loop is -// just annoying so I stopped doing it. But also there's another thing I find -// annoying: it's a copy every time. You're not really iterating over the -// values, you're iterating over copies of the values, it seemed like a lot of -// unecessary copying. -// // type Ator[T any] interface { // Next() (T, bool) // } diff --git a/iter/slice.go b/iter/slice.go index 0ea82b7..23b51b0 100644 --- a/iter/slice.go +++ b/iter/slice.go @@ -1,7 +1,5 @@ package iter -import "constraints" - type slice[T any] []T type sliceIter[T any] struct { @@ -22,5 +20,26 @@ func (it *sliceIter[T]) Iter() Ator[T] { return &sliceIter[T]{s: it.s} } func (s slice[T]) Iter() Ator[T] { return &sliceIter[T]{s: s} } -// Slice takes a slice and returns an iterable backed by that slice -func Slice[T constraints.Integer](s []T) Able[T] { return slice[T](s) } +// Slice takes a slice and returns an iterable backed by that slice. +// +// ok so, asn an aside: normally you would write a function to return the +// concrete implementation, not an interface, but if I return the concrete +// implementation for an iter.Able, the type inference doesn't work correctly +// with the type parameters in some cases. +// +// So let's say we had an exported type Slice that was defined as: +// +// type Slice[T any] []T +// +// And we tried to convert a []int to a Slice[int], we could so that with: +// +// Slice([]int{1, 2, 3}) +// +// And that would be fine until we try to do soething like pass it to Start. +// Returning Able[T] here means we can say Start(Slice([]int{1, 2, 3})), but if +// we had type Slice[T any] []T, we would have to say: +// +// Start[int](Slice([]int{1, 2, 3})) +// +// ...and I think that's annoying. +func Slice[T any](s []T) Able[T] { return slice[T](s) } diff --git a/iter/slice_test.go b/iter/slice_test.go new file mode 100644 index 0000000..e357887 --- /dev/null +++ b/iter/slice_test.go @@ -0,0 +1,19 @@ +package iter + +import ( + "testing" + "strconv" +) + +func TestSlice(t *testing.T) { + nums := []int{1, 2, 3, 4, 5} + s := Slice(nums) + for n, it := Start(s); it.Next(&n); { + t.Log(n) + } + + + for n, it := Start(Map(Slice(nums), strconv.Itoa)); it.Next(&n); { + t.Log("fart " + n) + } +} diff --git a/list/iter.go b/list/iter.go deleted file mode 100644 index 28a0fb6..0000000 --- a/list/iter.go +++ /dev/null @@ -1,56 +0,0 @@ -package list - -// type Iterable[T any] interface { -// Iter() Iter[T] -// } -// -// type Iter[T any] interface { -// Next(*T) bool -// } - -// for v, it := iter.Ate(foods); it.Next(&v); { -// -// } - -// This actually works, but for some reason I don't yet understand, defining -// Max with a constraint of constrains.Ordered that takes Iterable[T] cannot -// have its type parameter infered, but defining it with the same constraint of -// constraints.Ordered and taking List[T] does allow the type parameter to be -// inferred. Super confusing. -// -// func Max[T constraints.Ordered](l Iterable[T]) T { -// it := l.Iter() -// -// var v T -// if !it.Next(&v) { -// return v -// } -// max := v -// for it.Next(&v) { -// if v > max { -// max = v -// } -// } -// return max -// } - -// Discarded Iterator types: -// -// This was my first attempt. I like to have a method that returns a bool so -// you can use it succinctly in a for loop, but I didn't love having to call -// both done and next -// -// type Iter[T any] interface { -// Done() bool -// Next() T -// } -// -// I was never optimistic about this. In practice, using this in a for loop is -// just annoying so I stopped doing it. But also there's another thing I find -// annoying: it's a copy every time. You're not really iterating over the -// values, you're iterating over copies of the values, it seemed like a lot of -// unecessary copying. -// -// type Iter[T any] interface { -// Next() (T, bool) -// }