Skip to content

mikehelmick/go-functional

Repository files navigation

Go Reference CI workflow

go-functional

Functional programming primitives and OTP-inspired concurrency patterns for Go generics.

Requires Go 1.24+. See the documentation site for full API docs and examples.

Installation

go get github.com/mikehelmick/go-functional

Packages

Functional primitives

Package Description
slice Filter, Map, Fold, Find, Zip, Chunk, Sort, Dedup, Scan, and more
maps MapValues, FilterMap, Merge, MergeWith, Invert, Keys, ToSlice
optional Maybe[T] — Some or None with Map and GetOrElse
result Result[T] — wraps (T, error) with Map and chaining
pipeline Function composition: Pipe, Pipe2, Pipe3, Pipe4

OTP-inspired concurrency

Inspired by Elixir's OTP abstractions. Each package provides a typed, goroutine-safe building block.

Package Description
agent Goroutine-owned mutable state with Get / Update / Cast
genserver Generic request/response server loop — Call (sync) and Cast (async)
task Typed async work unit — Run, Await, AwaitAll, Map
supervisor Managed goroutine restart with OneForOne and OneForAll strategies

Quick examples

Slice operations

nums := []int{1, 2, 3, 4, 5, 6}

evens  := slice.Filter(nums, func(n int) bool { return n%2 == 0 })  // [2 4 6]
doubled := slice.Map(nums, func(n int) int { return n * 2 })         // [2 4 6 8 10 12]
sum    := slice.FoldL(nums, 0, func(acc, n int) int { return acc + n }) // 21
top3   := slice.Take(slice.SortBy(nums, func(n int) int { return -n }), 3) // [6 5 4]

Task — concurrent work

tasks := []*task.Task[int]{
    task.Run(func() (int, error) { return expensiveA() }),
    task.Run(func() (int, error) { return expensiveB() }),
    task.Run(func() (int, error) { return expensiveC() }),
}
results, err := task.AwaitAll(tasks) // waits for all, returns in order

Agent — shared mutable state

counter := agent.New(0)
counter.Update(func(n int) int { return n + 1 })
fmt.Println(counter.Get()) // 1
counter.Stop()

Supervisor — automatic restart

sup := supervisor.Start(supervisor.OneForOne, []supervisor.ChildSpec{
    {
        Name: "worker",
        Start: func(ctx context.Context) error {
            // Runs until ctx is cancelled.
            // Returning a non-nil error triggers an automatic restart.
            return runWorker(ctx)
        },
    },
})
defer sup.Stop()

GenServer — serialised state with call/cast

type CounterServer struct{}

func (CounterServer) Init() int                                  { return 0 }
func (CounterServer) HandleCall(req string, n int) (int, int)    { return n, n } // return current
func (CounterServer) HandleCast(req string, n int) int           { return n + 1 } // increment

srv := genserver.Start[int, string, int](CounterServer{})
srv.Cast("inc")
srv.Cast("inc")
fmt.Println(srv.Call("get")) // 2
srv.Stop()

Example application

See examples/wordfreq for an OTP-style word frequency service that combines supervisor, agent, task, pipeline, slice, and maps.

Attribution

Parts of this library were written with the assistance of Claude Code.

About

Functional programming like interfaces for Go.

Resources

License

Contributing

Stars

Watchers

Forks

Packages

 
 
 

Contributors