// MinMaxInt has a parametric type: // // func MinMaxInt(f func(A) int64, xs []A) (int64, int64) // // MinMaxInt returns the minimum and maximum values returned from f, if the list is // of length 0, it will return 0 and 0 func MinMaxInt(f, xs interface{}) (int64, int64) { chk := ty.Check( new(func(func(ty.A) int64, []ty.A)), f, xs) vp, vxs := chk.Args[0], chk.Args[1] xsLen := vxs.Len() if xsLen > 0 { min := call1(vp, vxs.Index(0)).Int() max := min for i := 1; i < xsLen; i++ { vx := vxs.Index(i) local := call1(vp, vx).Int() if local < min { min = local } if local > max { max = local } } return min, max } return 0, 0 }
// ParMapN has a parametric type: // // func ParMapN(f func(A) B, xs []A, n int) []B // // ParMapN is just like Map, except it applies `f` to each element in `xs` // concurrently using `n` worker goroutines. // // It is important that `f` not be a trivial operation, otherwise the overhead // of executing it concurrently will result in worse performance than using // a `Map`. func ParMapN(f, xs interface{}, n int) interface{} { chk := ty.Check( new(func(func(ty.A) ty.B, []ty.A) []ty.B), f, xs) vf, vxs, tys := chk.Args[0], chk.Args[1], chk.Returns[0] xsLen := vxs.Len() ys := reflect.MakeSlice(tys, xsLen, xsLen) if n < 1 { n = 1 } work := make(chan int, n) wg := new(sync.WaitGroup) for i := 0; i < n; i++ { wg.Add(1) go func() { for j := range work { // Good golly miss molly. Is `reflect.Value.Index` // safe to access/set from multiple goroutines? // XXX: If not, we'll need an extra wave of allocation to // use real slices of `reflect.Value`. ys.Index(j).Set(call1(vf, vxs.Index(j))) } wg.Done() }() } for i := 0; i < xsLen; i++ { work <- i } close(work) wg.Wait() return ys.Interface() }
// Sort has a parametric type: // // func Sort(less func(x1 A, x2 A) bool, []A) // // Sort uses the standard library `sort` package to sort `xs` in place. // // `less` should be a function that returns true if and only if `x1` is less // than `x2`. func Sort(less, xs interface{}) { chk := ty.Check( new(func(func(ty.A, ty.A) bool, []ty.A)), less, xs) vless, vxs := chk.Args[0], chk.Args[1] sort.Sort(&sortable{vless, vxs, swapperOf(vxs.Type().Elem())}) }
// Copy has a parametric type: // // func Copy(xs []A) []A // // Copy returns a copy of `xs` using Go's `copy` operation. func Copy(xs interface{}) interface{} { chk := ty.Check( new(func([]ty.A) []ty.A), xs) vxs, tys := chk.Args[0], chk.Returns[0] xsLen := vxs.Len() vys := reflect.MakeSlice(tys, xsLen, xsLen) reflect.Copy(vys, vxs) return vys.Interface() }
// Each has a parametric type: // // func Each(f func(A), xs []A) // // Each runs `f` across each element in `xs`. func Each(f, xs interface{}) { chk := ty.Check( new(func(func(ty.A), []ty.A)), f, xs) vf, vxs := chk.Args[0], chk.Args[1] xsLen := vxs.Len() for i := 0; i < xsLen; i++ { call(vf, vxs.Index(i)) } }
func First(slice interface{}) (elem interface{}) { chk := ty.Check( new(func([]ty.A) ty.A), slice) sliceVal, elemTyp := chk.Args[0], chk.Returns[0] if sliceVal.IsNil() || sliceVal.Len() == 0 { return reflect.Zero(elemTyp).Interface() } return sliceVal.Index(0).Interface() }
func Last(slice interface{}) (elem interface{}) { chk := ty.Check( new(func([]ty.A) ty.A), slice) vSlice, tElem := chk.Args[0], chk.Returns[0] if vSlice.IsNil() || vSlice.Len() == 0 { return reflect.Zero(tElem).Interface() } return vSlice.Index(vSlice.Len() - 1).Interface() }
// Values has a parametric type: // // func Values(m map[A]B) []B // // Values returns a list of the values of `m` in an unspecified order. func Values(m interface{}) interface{} { chk := ty.Check( new(func(map[ty.A]ty.B) []ty.B), m) vm, tvals := chk.Args[0], chk.Returns[0] vvals := reflect.MakeSlice(tvals, vm.Len(), vm.Len()) for i, vkey := range vm.MapKeys() { vvals.Index(i).Set(vm.MapIndex(vkey)) } return vvals.Interface() }
// Reverse has a parametric type: // // func Reverse(xs []A) []A // // Reverse returns a new slice that is the reverse of `xs`. func Reverse(xs interface{}) interface{} { chk := ty.Check( new(func([]ty.A) []ty.A), xs) vxs, tys := chk.Args[0], chk.Returns[0] xsLen := vxs.Len() vys := reflect.MakeSlice(tys, xsLen, xsLen) for i := 0; i < xsLen; i++ { vys.Index(i).Set(vxs.Index(xsLen - 1 - i)) } return vys.Interface() }
// CycleEach has a parametric type // // func CycleEach(f func(A), xs []A, n int) // // CycleEach calls each element of xs with f in order n times func CycleEach(f, xs interface{}, n int) { chk := ty.Check( new(func(func(ty.A), []ty.A, int)), f, xs, n) vp, vxs := chk.Args[0], chk.Args[1] xsLen := vxs.Len() for t := 0; t < n; t++ { for i := 0; i < xsLen; i++ { call(vp, vxs.Index(i)) } } }
// Concat has a parametric type: // // func Concat(xs [][]A) []A // // Concat returns a new flattened list by appending all elements of `xs`. func Concat(xs interface{}) interface{} { chk := ty.Check( new(func([][]ty.A) []ty.A), xs) vxs, tflat := chk.Args[0], chk.Returns[0] xsLen := vxs.Len() vflat := reflect.MakeSlice(tflat, 0, xsLen*3) for i := 0; i < xsLen; i++ { vflat = reflect.AppendSlice(vflat, vxs.Index(i)) } return vflat.Interface() }
// Count has a parametric type: // // func Count(f func(A) bool, xs []A) int // // Count returns the number of elements of xs for which f // returns true func Count(f, xs interface{}) (matches int) { chk := ty.Check( new(func(func(ty.A) bool, []ty.A)), f, xs) vp, vxs := chk.Args[0], chk.Args[1] xsLen := vxs.Len() for i := 0; i < xsLen; i++ { if call1(vp, vxs.Index(i)).Bool() { matches++ } } return }
// ShuffleGen has a parametric type: // // func ShuffleGen(xs []A, rng *rand.Rand) // // ShuffleGen shuffles `xs` in place using the given random number // generator `rng`. func ShuffleGen(xs interface{}, rng *rand.Rand) { chk := ty.Check( new(func([]ty.A, *rand.Rand)), xs, rng) vxs := chk.Args[0] // Implements the Fisher-Yates shuffle: http://goo.gl/Hb9vg xsLen := vxs.Len() swapper := swapperOf(vxs.Type().Elem()) for i := xsLen - 1; i >= 1; i-- { j := rng.Intn(i + 1) swapper.swap(vxs.Index(i), vxs.Index(j)) } }
// In has a parametric type: // // func In(needle A, haystack []A) bool // // In returns `true` if and only if `v` can be found in `xs`. The equality test // used is Go's standard `==` equality and NOT deep equality. // // Note that this requires that `A` be a type that can be meaningfully compared. func In(needle, haystack interface{}) bool { chk := ty.Check( new(func(ty.A, []ty.A) bool), needle, haystack) vhaystack := chk.Args[1] length := vhaystack.Len() for i := 0; i < length; i++ { if vhaystack.Index(i).Interface() == needle { return true } } return false }
// Exists has a parametric type: // // func Exists(p func(A) bool, xs []A) bool // // Exists returns `true` if and only if an element in `xs` satisfies `p`. func Exists(f, xs interface{}) bool { chk := ty.Check( new(func(func(ty.A) bool, []ty.A) bool), f, xs) vf, vxs := chk.Args[0], chk.Args[1] xsLen := vxs.Len() for i := 0; i < xsLen; i++ { if call1(vf, vxs.Index(i)).Interface().(bool) { return true } } return false }
// None has a parametric type // // func None(f func(A) bool, xs []A) bool // // None returns true if none of the elements in xs caused f to return // true, false otherwise func None(f, xs interface{}) bool { chk := ty.Check( new(func(func(ty.A) bool, []ty.A)), f, xs) vp, vxs := chk.Args[0], chk.Args[1] xsLen := vxs.Len() for i := 0; i < xsLen; i++ { if call1(vp, vxs.Index(i)).Bool() { return false } } return true }
// Set has a parametric type: // // func Set(xs []A) map[A]bool // // Set creates a set from a list. func Set(xs interface{}) interface{} { chk := ty.Check( new(func([]ty.A) map[ty.A]bool), xs) vxs, tset := chk.Args[0], chk.Returns[0] vtrue := reflect.ValueOf(true) vset := reflect.MakeMap(tset) xsLen := vxs.Len() for i := 0; i < xsLen; i++ { vset.SetMapIndex(vxs.Index(i), vtrue) } return vset.Interface() }
// Map has a parametric type: // // func Map(f func(A) B, xs []A) []B // // Map returns the list corresponding to the return value of applying // `f` to each element in `xs`. func Map(f, xs interface{}) interface{} { chk := ty.Check( new(func(func(ty.A) ty.B, []ty.A) []ty.B), f, xs) vf, vxs, tys := chk.Args[0], chk.Args[1], chk.Returns[0] xsLen := vxs.Len() vys := reflect.MakeSlice(tys, xsLen, xsLen) for i := 0; i < xsLen; i++ { vy := call1(vf, vxs.Index(i)) vys.Index(i).Set(vy) } return vys.Interface() }
// Detect has a parametric type: // // func Detect(f func(A) bool, xs []A) A // // Detect returns the first element for which f returns // true, if none are returned it returns nil func Detect(f, xs interface{}) interface{} { chk := ty.Check( new(func(func(ty.A) bool, []ty.A)), f, xs) vp, vxs := chk.Args[0], chk.Args[1] xsLen := vxs.Len() for i := 0; i < xsLen; i++ { if call1(vp, vxs.Index(i)).Bool() { return vxs.Index(i).Interface() } } return nil }
// SumFloat has a parametric type: // // func SumFloat(f func(A) float64, xs []A) float64 // // SumFloat returns the sum of the values returned from f func SumFloat(f, xs interface{}) float64 { chk := ty.Check( new(func(func(ty.A) float64, []ty.A)), f, xs) vp, vxs := chk.Args[0], chk.Args[1] xsLen := vxs.Len() var sum float64 for i := 0; i < xsLen; i++ { vx := vxs.Index(i) sum += call1(vp, vx).Float() } return sum }
// Difference has a parametric type: // // func Difference(a map[A]bool, b map[A]bool) map[A]bool // // Difference returns a set with all elements in `a` that are not in `b`. // The sets `a` and `b` are not modified. func Difference(a, b interface{}) interface{} { chk := ty.Check( new(func(map[ty.A]bool, map[ty.A]bool) map[ty.A]bool), a, b) va, vb, tc := chk.Args[0], chk.Args[1], chk.Returns[0] vtrue := reflect.ValueOf(true) vc := reflect.MakeMap(tc) for _, vkey := range va.MapKeys() { if !vb.MapIndex(vkey).IsValid() { vc.SetMapIndex(vkey, vtrue) } } return vc.Interface() }
// OrderedMap returns a new instance of OrdMap instantiated with the key // and value types given. Namely, the types should be provided via nil // pointers, e.g., to create a map from strings to integers: // // omap := OrderedMap(new(string), new(int)) // // An ordered map maintains the insertion order of all keys in the map. // Namely, `(*OrdMap).Keys()` returns a slice of keys in the order // they were inserted. The order of a key can *only* be changed if it is // deleted and added again. // // All of the operations on an ordered map have the same time complexity as // the built-in `map`, except for `Delete` which is O(n) in the number of // keys. func OrderedMap(ktype, vtype interface{}) *OrdMap { // A giant hack to get `Check` to do all the type construction work for us. chk := ty.Check( new(func(*ty.A, *ty.B) (ty.A, ty.B, map[ty.A]ty.B, []ty.A)), ktype, vtype) tkey, tval := chk.Returns[0], chk.Returns[1] tmap, tkeys := chk.Returns[2], chk.Returns[3] return &OrdMap{ m: reflect.MakeMap(tmap), keys: reflect.MakeSlice(tkeys, 0, 10), ktype: tkey, vtype: tval, } }
// Filter has a parametric type: // // func Filter(p func(A) bool, xs []A) []A // // Filter returns a new list only containing the elements of `xs` that satisfy // the predicate `p`. func Filter(p, xs interface{}) interface{} { chk := ty.Check( new(func(func(ty.A) bool, []ty.A) []ty.A), p, xs) vp, vxs, tys := chk.Args[0], chk.Args[1], chk.Returns[0] xsLen := vxs.Len() vys := reflect.MakeSlice(tys, 0, xsLen) for i := 0; i < xsLen; i++ { vx := vxs.Index(i) if call1(vp, vx).Bool() { vys = reflect.Append(vys, vx) } } return vys.Interface() }
// CycleMap has a parametric type // // func CycleMap(f func(A) B, xs []A, n int) []B // // CycleMap runs Map n times against xs with f and returns the result func CycleMap(f, xs interface{}, n int) interface{} { chk := ty.Check( new(func(func(ty.A) ty.B, []ty.A, int) []ty.B), f, xs, n) vp, vxs, tys := chk.Args[0], chk.Args[1], chk.Returns[0] xsLen := vxs.Len() vys := reflect.MakeSlice(tys, xsLen*n, xsLen*n) for t := 0; t < n; t++ { for i := 0; i < xsLen; i++ { vy := call1(vp, vxs.Index(i)) vys.Index(t*xsLen + i).Set(vy) } } return vys.Interface() }
// Replace has a parametric type // // func Replace(xs, ys []A) []A // // Replace changes elements of xs with elements of ys until one array is exhausted func Replace(xs, ys interface{}) interface{} { chk := ty.Check( new(func([]ty.A, []ty.A) []ty.A), xs, ys) vxs, vys, tzs := chk.Args[0], chk.Args[1], chk.Returns[0] xsLen, ysLen := vxs.Len(), vys.Len() vzs := reflect.MakeSlice(tzs, xsLen, xsLen) for i := 0; i < xsLen; i++ { if i < ysLen { vzs.Index(i).Set(vys.Index(i)) } else { vzs.Index(i).Set(vxs.Index(i)) } } return vzs.Interface() }
// QuickSort has a parametric type: // // func QuickSort(less func(x1 A, x2 A) bool, []A) []A // // QuickSort applies the "quicksort" algorithm to return a new sorted list // of `xs`, where `xs` is not modified. // // `less` should be a function that returns true if and only if `x1` is less // than `x2`. func QuickSort(less, xs interface{}) interface{} { chk := ty.Check( new(func(func(ty.A, ty.A) bool, []ty.A) []ty.A), less, xs) vless, vxs, tys := chk.Args[0], chk.Args[1], chk.Returns[0] var qsort func(left, right int) var partition func(left, right, pivot int) int xsind := Range(0, vxs.Len()) qsort = func(left, right int) { if left >= right { return } pivot := (left + right) / 2 pivot = partition(left, right, pivot) qsort(left, pivot-1) qsort(pivot+1, right) } partition = func(left, right, pivot int) int { vpivot := xsind[pivot] xsind[pivot], xsind[right] = xsind[right], xsind[pivot] ind := left for i := left; i < right; i++ { if call1(vless, vxs.Index(xsind[i]), vxs.Index(vpivot)).Bool() { xsind[i], xsind[ind] = xsind[ind], xsind[i] ind++ } } xsind[ind], xsind[right] = xsind[right], xsind[ind] return ind } // Sort `xsind` in place. qsort(0, len(xsind)-1) vys := reflect.MakeSlice(tys, len(xsind), len(xsind)) for i, xsIndex := range xsind { vys.Index(i).Set(vxs.Index(xsIndex)) } return vys.Interface() }
// ExpandSquareTable has a parametric type: // // func ExpandSquareTable([]A, int) ([]A, int) // // ExpandSquareTable takes any slice holding a square table of data (row-major) // and expands the length of the table to at least the length provided. A new // slice is returned (with data from `slice` copied to it) along with the // length of the table. // // This function is exported so that you may use it to build your own dense // tables (since the Table in this package can only store floats). func ExpandSquareTable(slice interface{}, leastLen int) (interface{}, int) { chk := ty.Check( new(func([]ty.A, int) []ty.A), slice, leastLen) vslice, tslice := chk.Args[0], chk.Returns[0] oldLen := int(math.Sqrt(float64(vslice.Cap()))) newLen := oldLen * 2 if newLen < leastLen { newLen = leastLen } rslice := reflect.MakeSlice(tslice, newLen*newLen, newLen*newLen) for r := 0; r < oldLen; r++ { for c := 0; c < oldLen; c++ { rslice.Index(r*newLen + c).Set(vslice.Index(r*oldLen + c)) } } return rslice.Interface(), newLen }
// Foldr has a parametric type: // // func Foldr(f func(A, B) B, init B, xs []A) B // // Foldr reduces a list of A to a single element B using a right fold with // an initial value `init`. func Foldr(f, init, xs interface{}) interface{} { chk := ty.Check( new(func(func(ty.A, ty.B) ty.B, ty.B, []ty.A) ty.B), f, init, xs) vf, vinit, vxs, tb := chk.Args[0], chk.Args[1], chk.Args[2], chk.Returns[0] xsLen := vxs.Len() vb := zeroValue(tb) vb.Set(vinit) if xsLen == 0 { return vb.Interface() } vb.Set(call1(vf, vxs.Index(xsLen-1), vb)) for i := xsLen - 2; i >= 0; i-- { vb.Set(call1(vf, vxs.Index(i), vb)) } return vb.Interface() }
// Memo has a parametric type: // // func Memo(f func(A) B) func(A) B // // Memo memoizes any function of a single argument that returns a single value. // The type `A` must be a Go type for which the comparison operators `==` and // `!=` are fully defined (this rules out functions, maps and slices). func Memo(f interface{}) interface{} { chk := ty.Check( new(func(func(ty.A) ty.B)), f) vf := chk.Args[0] saved := make(map[interface{}]reflect.Value) memo := func(in []reflect.Value) []reflect.Value { val := in[0].Interface() ret, ok := saved[val] if ok { return []reflect.Value{ret} } ret = call1(vf, in[0]) saved[val] = ret return []reflect.Value{ret} } return reflect.MakeFunc(vf.Type(), memo).Interface() }
// Drop has a parametric type: // // func Drop(f func(A) bool, xs []A) []A // // Drop calls f on each element of xs until it returns true, then returns // that element and the remaining elements of xs func Drop(f, xs interface{}) interface{} { chk := ty.Check( new(func(func(ty.A) bool, []ty.A) []ty.A), f, xs) vp, vxs, txs := chk.Args[0], chk.Args[1], chk.Returns[0] xsLen := vxs.Len() vys := reflect.MakeSlice(txs, 0, xsLen) found := false for i := 0; i < xsLen; i++ { vx := vxs.Index(i) if found || call1(vp, vx).Bool() { vys = reflect.Append(vys, vx) found = true } } return vys.Interface() }