proc is the first-class callable composite of go-composites — the Go analogue of Ruby's Proc/lambda. A Proc wraps a single function as a value you can pass around, invoke with Call, and chain with a railway-oriented Then. True to the org's discipline it is interface-first, never returns a bare nil, carries errors as a Result, and ships a Null-Object that is always safe to use.
compose threads a payload through a pipeline of steps. proc is one level down: it wraps a single callable as a first-class value. Then then lets you chain individual Procs railway-style — on success the payload of one becomes the single argument to the next; on error the chain short-circuits.
go get github.com/go-composites/proc@maintype Interface interface {
Call(args ...interface{}) Result.Interface // invoke the wrapped fn (nil fn -> error Result, no panic)
Then(next Interface) Interface // railway compose: feed payload to next on success, short-circuit on error
IsNull() bool
}
func New(fn func(args ...interface{}) Result.Interface) Interface // wrap a function as a Proc
func Null() Interface // the not-callable Null ProcSemantics:
New(fn)wrapsfnas aProc. AProcbuilt from anilfunction is still safe — itsCallreturns an errorResult("Proc.Call: nil function") rather than panicking.Call(args...)invokes the wrapped function and returns itsResult.Then(next)returns a newProcthat calls the receiver and, on a successfulResult, feeds that payload as the single argument tonext.Call(...). If the receiver yields an errorResult,Thenshort-circuits and returns it unchanged —nextis never called.Null()is the null-object:Callreturns"Proc.Null: not callable",Thenreturns theNullProc again, andIsNull()istrue.
import (
Proc "github.com/go-composites/proc/src"
Result "github.com/go-composites/result/src"
Error "github.com/go-composites/error/src"
)
parse := Proc.New(func(args ...interface{}) Result.Interface {
n, err := strconv.Atoi(args[0].(string))
if err != nil {
return Result.New(Result.WithError(Error.New("not an integer")))
}
return Result.New(Result.WithPayload(n))
})
double := Proc.New(func(args ...interface{}) Result.Interface {
return Result.New(Result.WithPayload(args[0].(int) * 2))
})
pipeline := parse.Then(double)
ok := pipeline.Call("21") // HasError=false, Payload=42
bad := pipeline.Call("not-a-number") // HasError=true, Error().Message()="not an integer" (double skipped)See main.go for a runnable demo of the success path, the short-circuit-on-error path, the nil-function guard, and the Null Proc.
BSD-3-Clause. See LICENSE.
