don't use this

master
Jordan Orelli 3 years ago
parent 9b9c986876
commit 1d343f3b22

@ -80,3 +80,24 @@ func Max[T constraints.Ordered](src Able[T]) T {
}
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 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)
// }

@ -0,0 +1,26 @@
package iter
import "constraints"
type slice[T any] []T
type sliceIter[T any] struct {
s slice[T]
i int
}
func (it *sliceIter[T]) Next(v *T) bool {
if it.i >= len(it.s) {
return false
}
*v = it.s[it.i]
it.i++
return true
}
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) }

@ -1,15 +1,15 @@
package list
type Iterable[T any] interface {
Iter() Iter[T]
}
type Iter[T any] interface {
Next(*T) bool
}
// 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
@ -20,7 +20,7 @@ type Iter[T any] interface {
//
// func Max[T constraints.Ordered](l Iterable[T]) T {
// it := l.Iter()
//
//
// var v T
// if !it.Next(&v) {
// return v
@ -34,7 +34,6 @@ type Iter[T any] interface {
// return max
// }
// Discarded Iterator types:
//
// This was my first attempt. I like to have a method that returns a bool so

@ -5,6 +5,8 @@ import (
"sync"
"constraints"
"fmt"
"github.com/jordanorelli/generic/iter"
)
type node[T any] struct {
@ -41,9 +43,6 @@ func Make[T any](vals ...T) List[T] {
return l
}
// func From[T any](it iter.Able) List[T] {
// }
// Empty is true for empty lists
func (l List[T]) Empty() bool {
return l.head == nil
@ -93,7 +92,9 @@ func (l List[T]) Head() T {
// Tail returns a list which is the original list without its Head element.
// If the original list is an empty list or a list of size 1, Tail is an
// empty list.
// empty list. Note that Tail creates a new list that is backed by the same
// elements as the old list; mutations on the origin list are visible in the
// tail and vice-versa.
func (l List[T]) Tail() List[T] {
if l.head == nil || l.head.next == nil {
return List[T]{}
@ -114,13 +115,13 @@ func (l List[T]) Len() int {
return i
}
type iter[T any] struct {
type _iter[T any] struct {
n *node[T]
}
func (i iter[T]) Done() bool { return i.n == nil }
func (i _iter[T]) Done() bool { return i.n == nil }
func (i *iter[T]) Next(dest *T) bool {
func (i *_iter[T]) Next(dest *T) bool {
if i.n == nil {
return false
}
@ -130,9 +131,9 @@ func (i *iter[T]) Next(dest *T) bool {
return true
}
func (l List[T]) Iter() Iter[T] {
return &iter[T]{n: l.head}
}
func (i *_iter[T]) Iter() iter.Ator[T] { return &_iter[T]{n: i.n} }
func (l List[T]) Iter() iter.Ator[T] { return &_iter[T]{n: l.head} }
func Max[T constraints.Ordered](l List[T]) T {
if l.Empty() {
@ -149,45 +150,81 @@ func Max[T constraints.Ordered](l List[T]) T {
return v
}
// Map exists as a method to permit chaining in the event that your input
// function maps T -> T. Since methods cannot have type parameters, mapping a
// function that transforms T -> Z is not possible as a method.
func (l List[T]) Map(f func(T) T) List[T] { return Map(l, f) }
// Map applies the input function f to each element of the list l, returning a
// new list containing the values produced by f
func (l List[T]) Map(f func(T) T) List[T] {
func Map[T any, Z any](l List[T], f func(T) Z) List[Z] {
if l.Empty() {
return List[T]{}
var empty List[Z]
return empty
}
mapped := List[T]{head: &node[T]{val: f(l.head.val)}}
mapped := List[Z]{head: &node[Z]{val: f(l.head.val)}}
last := mapped.head
for n := l.head.next; n != nil; n = n.next {
last.next = &node[T]{val: f(n.val)}
last.next = &node[Z]{val: f(n.val)}
last = last.next
}
return mapped
}
type numbered[T any] struct {
val T
i int
}
func waitNClose[T any](wg *sync.WaitGroup, c chan T) {
wg.Wait()
close(c)
}
// Run is the same as Map, but is run concurrently. The function f will be run
// for every element of l in its own goroutine.
// for every element of l in its own goroutine. The results of running f on
// each of the inputs will be stored into a new list in an order-preserving
// manner.
func Run[T any, Z any](l List[T], f func(T) Z) List[Z] {
if l.Empty() {
var empty List[Z]
return empty
}
// surprise: type declarations are not allowed inside of generic functions
//
// type numbered[T any] struct {
// val T
// i int
// }
var wg sync.WaitGroup
c := make(chan Z)
c := make(chan numbered[Z])
for n := l.head; n != nil; n = n.next {
i := 0
for n := l.head; n != nil; n = n.next{
wg.Add(1)
go func(v T) {
go func(v T, i int) {
defer wg.Done()
c <- f(v)
}(n.val)
c <- numbered[Z]{val: f(v), i: i}
}(n.val, i)
i++
}
go func() {
wg.Wait()
close(c)
}()
mem := make([]Z, i)
go waitNClose(&wg, c)
for z := range c {
mem[z.i] = z.val
}
var results List[Z]
for z := range c {
results.Push(z)
for i, _ := range mem {
results.head = &node[Z]{
val: mem[i],
next: results.head,
}
}
return results
}
@ -218,3 +255,23 @@ func (l List[T]) Filter(f func(T) bool) List[T] {
return passed
}
type Pair[T any, Z any] struct {
Left T
Right Z
}
// Zip takes two lists and joins them to create a list of pairs. It's the same
// as the python zip function, and totally stupid and Pair should not be in
// this package but I'm testing the iterable interfaces and this shows they are
// good, actually
func Zip[T any, Z any](left List[T], right List[Z]) List[Pair[T, Z]] {
lit, rit := left.Iter(), right.Iter()
var out List[Pair[T, Z]]
var next Pair[T, Z]
for lit.Next(&next.Left) && rit.Next(&next.Right) {
out.head = &node[Pair[T, Z]]{val: next, next: out.head}
}
return out
}

@ -2,6 +2,7 @@ package list
import (
"testing"
"time"
)
func TestEmpty(t *testing.T) {
@ -124,7 +125,18 @@ func TestMap(t *testing.T) {
eq(t, 0, nums.At(3))
eq(t, 30, Max(nums))
}
func TestRun(t *testing.T) {
sleep := func(n int) time.Duration {
dur := time.Duration(n) * time.Millisecond
time.Sleep(dur)
return dur
}
l := Make(1, 2, 3, 4, 5, 4, 3, 2, 1)
durs := Run(l, sleep)
t.Logf("%v", durs)
}
func TestIter(t *testing.T) {

@ -6,6 +6,7 @@ import (
"github.com/jordanorelli/generic/iter"
)
// Span represents some range of integers
type Span[T constraints.Integer] struct {
Start T
End T

@ -24,7 +24,7 @@ func TestSpan(t *testing.T) {
// can be inferred, but when New returns a value of Span[T] (which
// satisfies iter.Able[T]), the type parameter cannot be inferred. I don't
// know why this behavior exists or if this is the intended behavior.
// +
// |
// |
// V
beer := iter.Max[int](New(1, 100))
@ -37,6 +37,20 @@ func TestSpan(t *testing.T) {
t.Errorf("expected 30 to be old but saw %d instead", old)
}
// honestly a very ridiculous use-case, but I'm looking at some weird
// inferrence corner cases. It seems the third parameter can't be the
// literal 2, you have to explicitly type it.
alpha := Step('a', 'z'+1, rune(2))
// the rune type can't be inferred here either
for a, it := iter.Start[rune](alpha); it.Next(&a); {
t.Logf("%c", a)
}
// the rune type can't be inferred here either!
for a, it := iter.Start[rune](alpha.Iter()); it.Next(&a); {
}
t.Logf("%T", iter.Max[int8](New[int8](3, 10)))
}

Loading…
Cancel
Save