This is a minimum working example to explore the usage of first class functions as presented by Dave Cheney.
- https://dave.cheney.net/2016/11/13/do-not-fear-first-class-functions
- https://www.youtube.com/watch?v=5buaPyJ0XeQ
(On the same topic Rob Pike also wrote an interesting article: https://commandcenter.blogspot.co.uk/2014/01/self-referential-functions-and-design.html)
package boom
import (
"math"
"testing"
)
// Calculator is the struct containing the accumulator (the state)
type Calculator struct {
acc float64
}
// Opfunc is the function type representing the operation to be performed
type Opfunc func(float64) float64
// Do performs an operation on the function type Opfunc
func (c *Calculator) Do(op Opfunc) float64 {
c.acc = op(c.acc)
return c.acc
}
// Add allows the flexibility to pass some input parameters to be combined
// inside Opfunc
func Add(n float64) Opfunc {
return func(acc float64) float64 {
return acc + n
}
}
// Sqrt is providing an implementation of Opfunc without the need
// to pass any input parameter
func Sqrt() Opfunc {
return func(n float64) float64 {
return math.Sqrt(n)
}
}
// Compose iterates over the variadic input to apply all the Opfunc implementations
func (c *Calculator) Compose(ops ...Opfunc) {
for _, op := range ops {
c.Do(op)
}
}
func TestDo(t *testing.T) {
var c Calculator
c.Do(Add(2))
c.Do(Sqrt())
if c.acc < 1.41421356237 {
t.Error("AAAHHH!!!")
}
}
func TestCompose(t *testing.T) {
var c Calculator
c.Compose(Add(2), Sqrt())
if c.acc < 1.41421356237 {
t.Error("AAAHHH!!!")
}
}