Skip to content

Commit

Permalink
interface is back
Browse files Browse the repository at this point in the history
  • Loading branch information
rushsteve1 committed Nov 4, 2024
1 parent c07db1b commit 67e56ce
Show file tree
Hide file tree
Showing 16 changed files with 216 additions and 128 deletions.
2 changes: 1 addition & 1 deletion threading/chain.go → fun/chain.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package threading
package fun

import (
"fmt"
Expand Down
2 changes: 1 addition & 1 deletion threading/chain_test.go → fun/chain_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package threading
package fun

import (
"strconv"
Expand Down
2 changes: 1 addition & 1 deletion threading/curry.go → fun/curry.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package threading
package fun

import (
"fmt"
Expand Down
2 changes: 1 addition & 1 deletion threading/curry_test.go → fun/curry_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package threading
package fun

import "testing"

Expand Down
23 changes: 23 additions & 0 deletions fun/fun.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package fun

import "github.com/rushsteve1/fp"

func Identity[T any](t T) T {
return t
}


// Errorless takes a function that can error and returns a new function that
// wraps the provided one in [fp.Must]
func Errorless[T, U any](f func(T) (U, error)) func(T) U {
return func(t T) U {
return fp.Must(f(t))
}
}

// Discard takes a function and returns a new wrapping function without the return value
func Discard[T, U any](f func(T) U) func(T) {
return func(t T) {
_ = f(t)
}
}
37 changes: 18 additions & 19 deletions generators/generators.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,96 +2,95 @@ package generators

import (
"io"
. "iter"
"net"
"time"

"github.com/rushsteve1/fp"
. "github.com/rushsteve1/fp"
)

// A generator is any function that returns a new sequence

// Empty returns an infinite empty sequence that never yields any values
func Empty[T any]() Seq[T] {
return func(func(T) bool){}
return SeqFunc[T](func(func(T) bool){})
}

// Generate returns an iterator that repeatedly calls the provided function,
// yielding the values it returns
func Generate[T any](f func() T) Seq[T] {
return func(yield func(T) bool) {
return SeqFunc[T](func(yield func(T) bool) {
if !yield(f()) {
return
}
}
})
}

// Forever returns an infinite sequence of the provided value
func Forever[T any](v T) Seq[T] {
return func(yield func(T) bool){
return SeqFunc[T](func(yield func(T) bool){
if !yield(v) {
return
}
}
})
}

// Integers yields an infinite sequence of integers
func Integers() Seq[int] {
return func(yield func(int) bool) {
return SeqFunc[int](func(yield func(int) bool) {
n := 0
for yield(n) {
n++
}
}
})
}

// Ticker yields the current time when the duration has passed
func Ticker(d time.Duration) Seq[time.Time] {
return func(yield func(time.Time) bool) {
return SeqFunc[time.Time](func(yield func(time.Time) bool) {
for t := range time.Tick(d) {
if !yield(t) {
return
}
}
}
})
}

// Chan returns an iterator that continually yields values from the channel.
// The channel is closed if the sequence stops.
// It is the caller's responsibility to close the channel to prevent deadlocks
func Chan[T any](c chan T) Seq[T] {
return func(yield func(T) bool) {
return SeqFunc[T](func(yield func(T) bool) {
for t := range c {
if !yield(t) {
close(c)
return
}
}
}
})
}

// Reader reads from the passed [io.Reader] turning into a sequence of byte arrays.
// See its counterpart [transducers.Writer]
func Reader(r io.Reader) Seq[[]byte] {
return func(yield func([]byte) bool) {
return SeqFunc[[]byte](func(yield func([]byte) bool) {
var buf []byte
fp.Must(r.Read(buf))
Must(r.Read(buf))
if !yield(buf) {
return
}
}
})
}

// Accept takes a listener and returns a sequence of accepted connections.
// The listener is closed if the sequence stops.
func Accept(l net.Listener) Seq[net.Conn] {
return func(yield func(net.Conn) bool) {
return SeqFunc[net.Conn](func(yield func(net.Conn) bool) {
for {
c := fp.Must(l.Accept())
c := Must(l.Accept())
if !yield(c) {
l.Close()
return
}
}
}
})
}
4 changes: 2 additions & 2 deletions generators/generators_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (

func TestTicker(t *testing.T) {
i := 0
for _ = range Ticker(time.Millisecond * 100) {
for _ = range Ticker(time.Millisecond * 100).Seq {
if i > 5 {
break
}
Expand All @@ -29,7 +29,7 @@ func TestChan(t *testing.T) {
}()

i := 0
for v := range s {
for v := range s.Seq {
t.Log(v)
i++
}
Expand Down
49 changes: 49 additions & 0 deletions iter.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// This package wraps the standard library's [iter] package, providing some
// additional features.
//
// It is intended to potentially inform future development and act as the
// backbone of this library.

package fp

import (
"iter"
)

// SeqFunc is exactly the same as [iter.Seq] and can be trivially cast between
type SeqFunc[V any] iter.Seq[V]

// Seq borrows a trick used by [http.Handler] to define an interface and a func
// that implements that interface by calling itself [SeqFunc]
type Seq[V any] interface {
// Seq implements push-style iteration using the yield callback.
// See the documenation of [iter] for more information.
// It has exactly the same signature as [SeqFunc].
Seq(yield func(V) bool)
}

func (sf SeqFunc[V]) Seq(yield func(V) bool) {
sf(yield)
}

// Seq2Func is exactly the same as [iter.Seq2] and can be trivially cast between
type Seq2Func[K, V any] iter.Seq2[K, V]

// Seq2 is to [Seq] what [iter.Seq] is to [iter.Seq2]
type Seq2[K, V any] interface {
Seq2(yield func(K, V) bool)
}

func (sf Seq2Func[K, V]) Seq2(yield func(K, V) bool) {
sf(yield)
}

// Pull is a wrappr around [iter.Pull]
func Pull[V any](seq Seq[V]) (next func() (V, bool), stop func()) {
return iter.Pull(seq.Seq)
}

// Pull2 is a wrapper around [iter.Pull2]
func Pull2[K, V any](seq Seq2[K, V]) (next func() (K, V, bool), stop func()) {
return iter.Pull2(seq.Seq2)
}
45 changes: 25 additions & 20 deletions magic.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,20 @@ package fp

import (
"cmp"
"runtime"
"slices"
"testing"
)

var GlobalErrorHandler = func(err error) {
var GlobalErrorHandler = func(err error) bool {
panic(err)
}

func Identity[T any](t T) T {
return t
}

func Check(err error) {
if err != nil {
GlobalErrorHandler(err)
if !GlobalErrorHandler(err) {
runtime.Goexit()
}
}
}

Expand All @@ -37,20 +38,6 @@ func Must[T any](t T, err error) T {
return t
}

// Errorless takes a function that can error and returns a new function that
// wraps the provided one in [fp.Must]
func Errorless[T, U any](f func(T) (U, error)) func(T) U {
return func(t T) U {
return Must(f(t))
}
}

func Discard[T, U any](f func(T) U) func(T) {
return func(t T) {
_ = f(t)
}
}

func Clamp[T cmp.Ordered](x T, lo T, hi T) T {
return max(min(x, hi), lo)
}
Expand All @@ -73,3 +60,21 @@ func Ternary[T any](cond bool, a T, b T) T {
}
return b
}

func Assert(t *testing.T, cond bool) {
if !cond {
t.Error("Assertion failure")
}
}

func AssertEq[T comparable](t *testing.T, a, b T) {
if a != b {
t.Errorf("Assertion failure: %+v != %+v", a, b)
}
}

func AssertSliceEq[S ~[]E, E comparable](t *testing.T, a, b S) {
if !slices.Equal(a, b) {
t.Errorf("Assertion failure: %+v != %+v", a, b)
}
}
8 changes: 5 additions & 3 deletions monads/monads.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package monads

import (
)
import "github.com/rushsteve1/fp"

// Monad is a context that an operation took place in.
// You can apply additional operations to
type Monad[T any] interface {
fp.Seq[T]
Ok() bool
Get() (T, error)
Seq(yield func(T) bool)
}
4 changes: 4 additions & 0 deletions monads/option.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ func None[T any]() Option[T] {
}
}

func (o Option[T]) Ok() bool {
return o.Valid
}

func (o Option[T]) Get() (T, error) {
return o.V, fp.Ternary(o.Valid, nil, ErrUnwrapInvalid)
}
Expand Down
4 changes: 4 additions & 0 deletions monads/result.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ func Wrap[T any](v T, err error) Result[T] {
}
}

func (o Result[T]) Ok() bool {
return o.Err != nil
}

func (r Result[T]) Get() (T, error) {
return r.V, r.Err
}
Expand Down
Loading

0 comments on commit 67e56ce

Please sign in to comment.