Skip to content

Instantly share code, notes, and snippets.

@marz619
Last active April 15, 2024 17:55
Show Gist options
  • Save marz619/6bbbbe0323899a6cc4b59ea30bbaadef to your computer and use it in GitHub Desktop.
Save marz619/6bbbbe0323899a6cc4b59ea30bbaadef to your computer and use it in GitHub Desktop.
Composition & Higher-Order Functions in Golang (via: https://faiface.github.io/post/how-i-built-audio-lib-composite-pattern/)
package fun
// bufferedSequence
type bufferedSeq struct {
seq Seq // original Seq
buf *[]float64 // shared slice
pos int // this pos
}
// Next implements Seq interface
func (bs *bufferedSeq) Next() (float64, bool) {
// need new elem from sequence
if bs.pos >= len(*bs.buf) {
v, ok := bs.seq.Next()
if !ok {
return v, ok
}
*bs.buf = append(*bs.buf, v)
}
// otherwise buffer has advanced
v := (*bs.buf)[bs.pos]
bs.pos++
return v, true
}
func bufferedSeqs(n int, seq Seq) []Seq {
buf := make([]float64, 0)
bufSeqs := make([]Seq, n)
for i := range bufSeqs {
bufSeqs[i] = newBufferedSeq(seq, &buf)
}
return bufSeqs
}
func newBufferedSeq(seq Seq, buf *[]float64) Seq {
return &bufferedSeq{seq: seq, buf: buf}
}
package fun
// Expr is a function type that yields a float64
// i.e. an Expression of float64
type Expr func() float64
// Const returns an Expr that always yields x
func Const(c float64) Expr {
return func() float64 {
return c
}
}
// Ref returns an Expr that yields the value of x
func Ref(r *float64) Expr {
return func() float64 {
return *r
}
}
// Sum returns an Expr that will yield the sum
// of the provided expressions
func Sum(exprs ...Expr) Expr {
return func() float64 {
sum := 0.0
for _, ex := range exprs {
sum += ex()
}
return sum
}
}
package fun
// Seq is a sequence interface
type Seq interface {
Next() (float64, bool)
}
// SeqFunc implements the Seq interface
type SeqFunc func() (float64, bool)
// Next returns the value generated by the SeqFunc
func (sf SeqFunc) Next() (float64, bool) {
return sf()
}
// Make returns a Seq from a series of values
func Make(vals ...float64) Seq {
// index tracker
i := 0
// our func
sf := func() (float64, bool) {
if i >= len(vals) {
return 0, false
}
x := vals[i]
i++
return x, true
}
return SeqFunc(sf)
}
// Collect the values of a Seq and return it as a slice
func Collect(seq Seq, hint ...int) []float64 {
var vals []float64
if len(hint) > 0 && hint[0] > 0 {
vals = make([]float64, 0, hint[0])
}
for {
if v, ok := seq.Next(); ok {
vals = append(vals, v)
continue
}
break
}
return vals
}
// Take n items from a Seq
func Take(n int, seq Seq) Seq {
sf := func() (float64, bool) {
if n <= 0 {
return 0, false
}
n--
return seq.Next()
}
return SeqFunc(sf)
}
// Split a Seq at some index n
func Split(n int, seq Seq) (Seq, Seq) {
return Make(Collect(Take(n, seq))...), seq
}
// Dup returns two Seqs identical to the provided Seq
//
// This assumes the original Seq will not be pre-emptively
// consumed. Additionally, this is not safe for concurrent
// use.
func Dup(seq Seq) (Seq, Seq) {
dup := bufferedSeqs(2, seq)
return dup[0], dup[1]
}
package fun
// Naturals is the infinite series of natural numbers
func Naturals() Seq {
n := 0.0
sf := func() (float64, bool) {
n++
return n, true
}
return SeqFunc(sf)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment