diff --git a/func.go b/func.go index 5fa1cbc8..f1d1ef9f 100644 --- a/func.go +++ b/func.go @@ -1,41 +1,254 @@ package lo -// Partial returns new function that, when called, has its first argument set to the provided value. -func Partial[T1, T2, R any](f func(a T1, b T2) R, arg1 T1) func(T2) R { +// Func is a function with 0 argument and 1 return value (null-ary function). +type Func[R any] func() R + +// Func1 is a function with 1 argument and 1 return value (unary function), +// which supports partial application. +type Func1[T1, R any] func(T1) R + +// MFunc1 casts function f with 1 argument and 1 return value to Func1. +func MFunc1[T1, R any](f Func1[T1, R]) Func1[T1, R] { + return f +} + +// Partial binds the first argument (from left to right) of Func1 f to value t1, +// producing Func of smaller arity. +func (f Func1[T1, R]) Partial(t1 T1) Func[R] { + return func() R { + return f(t1) + } +} + +// PartialR binds the first argument (from right to left) of Func1 f to value t1, +// producing Func of smaller arity. +func (f Func1[T1, R]) PartialR(t1 T1) Func[R] { + return func() R { + return f(t1) + } +} + +// Func2 is a function with 2 arguments and 1 return value (2-ary function), +// which supports partial application. +type Func2[T1, T2, R any] func(T1, T2) R + +// MFunc2 casts function f with 2 arguments and 1 return value to Func2 +func MFunc2[T1, T2, R any](f Func2[T1, T2, R]) Func2[T1, T2, R] { + return f +} + +// Partial binds the first argument (from left to right) of Func2 f to value t1, +// producing Func1 of smaller arity. +func (f Func2[T1, T2, R]) Partial(t1 T1) Func1[T2, R] { return func(t2 T2) R { - return f(arg1, t2) + return f(t1, t2) } } -// Partial1 returns new function that, when called, has its first argument set to the provided value. -func Partial1[T1, T2, R any](f func(T1, T2) R, arg1 T1) func(T2) R { - return Partial(f, arg1) +// PartialR binds the first argument (from right to left) of Func2 f to value t2, +// producing Func1 of smaller arity. +func (f Func2[T1, T2, R]) PartialR(t2 T2) Func1[T1, R] { + return func(t1 T1) R { + return f(t1, t2) + } } -// Partial2 returns new function that, when called, has its first argument set to the provided value. -func Partial2[T1, T2, T3, R any](f func(T1, T2, T3) R, arg1 T1) func(T2, T3) R { +// Func3 is a function with 3 arguments and 1 return value (3-ary function), +// which supports partial application. +type Func3[T1, T2, T3, R any] func(T1, T2, T3) R + +// MFunc3 casts function f with 3 arguments and 1 return value to Func3 +func MFunc3[T1, T2, T3, R any](f Func3[T1, T2, T3, R]) Func3[T1, T2, T3, R] { + return f +} + +// Partial binds the first argument (from left to right) of Func3 f to value t1, +// producing Func2 of smaller arity. +func (f Func3[T1, T2, T3, R]) Partial(t1 T1) Func2[T2, T3, R] { return func(t2 T2, t3 T3) R { - return f(arg1, t2, t3) + return f(t1, t2, t3) } } -// Partial3 returns new function that, when called, has its first argument set to the provided value. -func Partial3[T1, T2, T3, T4, R any](f func(T1, T2, T3, T4) R, arg1 T1) func(T2, T3, T4) R { +// PartialR binds the first argument (from right to left) of Func3 f to value t3, +// producing Func2 of smaller arity. +func (f Func3[T1, T2, T3, R]) PartialR(t3 T3) Func2[T1, T2, R] { + return func(t1 T1, t2 T2) R { + return f(t1, t2, t3) + } +} + +// Func4 is a function with 4 arguments and 1 return value (4-ary function), +// which supports partial application. +type Func4[T1, T2, T3, T4, R any] func(T1, T2, T3, T4) R + +// MFunc4 casts function f with 4 arguments and 1 return value to Func4 +func MFunc4[T1, T2, T3, T4, R any](f Func4[T1, T2, T3, T4, R]) Func4[T1, T2, T3, T4, R] { + return f +} + +// Partial binds the first argument (from left to right) of Func4 f to value t1, +// producing Func3 of smaller arity. +func (f Func4[T1, T2, T3, T4, R]) Partial(t1 T1) Func3[T2, T3, T4, R] { return func(t2 T2, t3 T3, t4 T4) R { - return f(arg1, t2, t3, t4) + return f(t1, t2, t3, t4) } } -// Partial4 returns new function that, when called, has its first argument set to the provided value. -func Partial4[T1, T2, T3, T4, T5, R any](f func(T1, T2, T3, T4, T5) R, arg1 T1) func(T2, T3, T4, T5) R { +// PartialR binds the first argument (from right to left) of Func4 f to value t4, +// producing Func3 of smaller arity. +func (f Func4[T1, T2, T3, T4, R]) PartialR(t4 T4) Func3[T1, T2, T3, R] { + return func(t1 T1, t2 T2, t3 T3) R { + return f(t1, t2, t3, t4) + } +} + +// Func5 is a function with 5 arguments and 1 return value (5-ary function), +// which supports partial application. +type Func5[T1, T2, T3, T4, T5, R any] func(T1, T2, T3, T4, T5) R + +// MFunc5 casts function f with 5 arguments and 1 return value to Func5 +func MFunc5[T1, T2, T3, T4, T5, R any](f Func5[T1, T2, T3, T4, T5, R]) Func5[T1, T2, T3, T4, T5, R] { + return f +} + +// Partial binds the first argument (from left to right) of Func5 f to value t1, +// producing Func4 of smaller arity. +func (f Func5[T1, T2, T3, T4, T5, R]) Partial(t1 T1) Func4[T2, T3, T4, T5, R] { return func(t2 T2, t3 T3, t4 T4, t5 T5) R { - return f(arg1, t2, t3, t4, t5) + return f(t1, t2, t3, t4, t5) } } -// Partial5 returns new function that, when called, has its first argument set to the provided value -func Partial5[T1, T2, T3, T4, T5, T6, R any](f func(T1, T2, T3, T4, T5, T6) R, arg1 T1) func(T2, T3, T4, T5, T6) R { +// PartialR binds the first argument (from right to left) of Func5 f to value t5, +// producing Func4 of smaller arity. +func (f Func5[T1, T2, T3, T4, T5, R]) PartialR(t5 T5) Func4[T1, T2, T3, T4, R] { + return func(t1 T1, t2 T2, t3 T3, t4 T4) R { + return f(t1, t2, t3, t4, t5) + } +} + +// Func6 is a function with 6 arguments and 1 return value (6-ary function), +// which supports partial application. +type Func6[T1, T2, T3, T4, T5, T6, R any] func(T1, T2, T3, T4, T5, T6) R + +// MFunc6 casts function f with 6 arguments and 1 return value to Func6 +func MFunc6[T1, T2, T3, T4, T5, T6, R any](f Func6[T1, T2, T3, T4, T5, T6, R]) Func6[T1, T2, T3, T4, T5, T6, R] { + return f +} + +// Partial binds the first argument (from left to right) of Func6 f to value t1, +// producing Func5 of smaller arity. +func (f Func6[T1, T2, T3, T4, T5, T6, R]) Partial(t1 T1) Func5[T2, T3, T4, T5, T6, R] { return func(t2 T2, t3 T3, t4 T4, t5 T5, t6 T6) R { - return f(arg1, t2, t3, t4, t5, t6) + return f(t1, t2, t3, t4, t5, t6) + } +} + +// PartialR binds the first argument (from right to left) of Func6 f to value t6, +// producing Func5 of smaller arity. +func (f Func6[T1, T2, T3, T4, T5, T6, R]) PartialR(t6 T6) Func5[T1, T2, T3, T4, T5, R] { + return func(t1 T1, t2 T2, t3 T3, t4 T4, t5 T5) R { + return f(t1, t2, t3, t4, t5, t6) + } +} + +// Func7 is a function with 7 arguments and 1 return value (7-ary function), +// which supports partial application. +type Func7[T1, T2, T3, T4, T5, T6, T7, R any] func(T1, T2, T3, T4, T5, T6, T7) R + +// MFunc7 casts function f with 7 arguments and 1 return value to Func7 +func MFunc7[T1, T2, T3, T4, T5, T6, T7, R any](f Func7[T1, T2, T3, T4, T5, T6, T7, R]) Func7[T1, T2, T3, T4, T5, T6, T7, R] { + return f +} + +// Partial binds the first argument (from left to right) of Func7 f to value t1, +// producing Func6 of smaller arity. +func (f Func7[T1, T2, T3, T4, T5, T6, T7, R]) Partial(t1 T1) Func6[T2, T3, T4, T5, T6, T7, R] { + return func(t2 T2, t3 T3, t4 T4, t5 T5, t6 T6, t7 T7) R { + return f(t1, t2, t3, t4, t5, t6, t7) + } +} + +// PartialR binds the first argument (from right to left) of Func7 f to value t7, +// producing Func6 of smaller arity. +func (f Func7[T1, T2, T3, T4, T5, T6, T7, R]) PartialR(t7 T7) Func6[T1, T2, T3, T4, T5, T6, R] { + return func(t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6) R { + return f(t1, t2, t3, t4, t5, t6, t7) + } +} + +// Func8 is a function with 8 arguments and 1 return value (8-ary function), +// which supports partial application. +type Func8[T1, T2, T3, T4, T5, T6, T7, T8, R any] func(T1, T2, T3, T4, T5, T6, T7, T8) R + +// MFunc8 casts function f with 8 arguments and 1 return value to Func8 +func MFunc8[T1, T2, T3, T4, T5, T6, T7, T8, R any](f Func8[T1, T2, T3, T4, T5, T6, T7, T8, R]) Func8[T1, T2, T3, T4, T5, T6, T7, T8, R] { + return f +} + +// Partial binds the first argument (from left to right) of Func8 f to value t1, +// producing Func7 of smaller arity. +func (f Func8[T1, T2, T3, T4, T5, T6, T7, T8, R]) Partial(t1 T1) Func7[T2, T3, T4, T5, T6, T7, T8, R] { + return func(t2 T2, t3 T3, t4 T4, t5 T5, t6 T6, t7 T7, t8 T8) R { + return f(t1, t2, t3, t4, t5, t6, t7, t8) + } +} + +// PartialR binds the first argument (from right to left) of Func8 f to value t8, +// producing Func7 of smaller arity. +func (f Func8[T1, T2, T3, T4, T5, T6, T7, T8, R]) PartialR(t8 T8) Func7[T1, T2, T3, T4, T5, T6, T7, R] { + return func(t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6, t7 T7) R { + return f(t1, t2, t3, t4, t5, t6, t7, t8) + } +} + +// Func9 is a function with 9 arguments and 1 return value (9-ary function), +// which supports partial application. +type Func9[T1, T2, T3, T4, T5, T6, T7, T8, T9, R any] func(T1, T2, T3, T4, T5, T6, T7, T8, T9) R + +// MFunc9 casts function f with 9 arguments and 1 return value to Func9 +func MFunc9[T1, T2, T3, T4, T5, T6, T7, T8, T9, R any](f Func9[T1, T2, T3, T4, T5, T6, T7, T8, T9, R]) Func9[T1, T2, T3, T4, T5, T6, T7, T8, T9, R] { + return f +} + +// Partial binds the first argument (from left to right) of Func9 f to value t1, +// producing Func8 of smaller arity. +func (f Func9[T1, T2, T3, T4, T5, T6, T7, T8, T9, R]) Partial(t1 T1) Func8[T2, T3, T4, T5, T6, T7, T8, T9, R] { + return func(t2 T2, t3 T3, t4 T4, t5 T5, t6 T6, t7 T7, t8 T8, t9 T9) R { + return f(t1, t2, t3, t4, t5, t6, t7, t8, t9) + } +} + +// PartialR binds the first argument (from right to left) of Func9 f to value t9, +// producing Func8 of smaller arity. +func (f Func9[T1, T2, T3, T4, T5, T6, T7, T8, T9, R]) PartialR(t9 T9) Func8[T1, T2, T3, T4, T5, T6, T7, T8, R] { + return func(t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6, t7 T7, t8 T8) R { + return f(t1, t2, t3, t4, t5, t6, t7, t8, t9) + } +} + +// Func10 is a function with 10 arguments and 1 return value (10-ary function), +// which supports partial application. +type Func10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, R any] func(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10) R + +// MFunc10 casts function f with 10 arguments and 1 return value to Func10 +func MFunc10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, R any](f Func10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, R]) Func10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, R] { + return f +} + +// Partial binds the first argument (from left to right) of Func10 f to value t1, +// producing Func9 of smaller arity. +func (f Func10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, R]) Partial(t1 T1) Func9[T2, T3, T4, T5, T6, T7, T8, T9, T10, R] { + return func(t2 T2, t3 T3, t4 T4, t5 T5, t6 T6, t7 T7, t8 T8, t9 T9, t10 T10) R { + return f(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10) + } +} + +// PartialR binds the first argument (from right to left) of Func10 f to value t10, +// producing Func9 of smaller arity. +func (f Func10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, R]) PartialR(t10 T10) Func9[T1, T2, T3, T4, T5, T6, T7, T8, T9, R] { + return func(t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6, t7 T7, t8 T8, t9 T9) R { + return f(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10) } } diff --git a/func_test.go b/func_test.go index 284d24a4..60679805 100644 --- a/func_test.go +++ b/func_test.go @@ -1,80 +1,58 @@ package lo import ( - "strconv" "testing" "github.com/stretchr/testify/assert" ) -func TestPartial(t *testing.T) { - t.Parallel() - is := assert.New(t) - - add := func(x float64, y int) string { - return strconv.Itoa(int(x) + y) - } - f := Partial(add, 5) - is.Equal("15", f(10)) - is.Equal("0", f(-5)) -} - -func TestPartial1(t *testing.T) { - t.Parallel() - is := assert.New(t) - - add := func(x float64, y int) string { - return strconv.Itoa(int(x) + y) - } - f := Partial1(add, 5) - is.Equal("15", f(10)) - is.Equal("0", f(-5)) -} - -func TestPartial2(t *testing.T) { - t.Parallel() - is := assert.New(t) - - add := func(x float64, y int, z int) string { - return strconv.Itoa(int(x) + y + z) - } - f := Partial2(add, 5) - is.Equal("24", f(10, 9)) - is.Equal("8", f(-5, 8)) +func TestPartialFunc2(t *testing.T) { + add := MFunc2(func(a, b int) int { + return a + b + }) + assert.Equal(t, 3, add.Partial(1).Partial(2)()) + assert.Equal(t, 3, add.PartialR(1).PartialR(2)()) } -func TestPartial3(t *testing.T) { - t.Parallel() - is := assert.New(t) - - add := func(x float64, y int, z int, a float32) string { - return strconv.Itoa(int(x) + y + z + int(a)) - } - f := Partial3(add, 5) - is.Equal("21", f(10, 9, -3)) - is.Equal("15", f(-5, 8, 7)) -} - -func TestPartial4(t *testing.T) { - t.Parallel() - is := assert.New(t) - - add := func(x float64, y int, z int, a float32, b int32) string { - return strconv.Itoa(int(x) + y + z + int(a) + int(b)) - } - f := Partial4(add, 5) - is.Equal("21", f(10, 9, -3, 0)) - is.Equal("14", f(-5, 8, 7, -1)) -} - -func TestPartial5(t *testing.T) { - t.Parallel() - is := assert.New(t) - - add := func(x float64, y int, z int, a float32, b int32, c int) string { - return strconv.Itoa(int(x) + y + z + int(a) + int(b) + c) - } - f := Partial5(add, 5) - is.Equal("26", f(10, 9, -3, 0, 5)) - is.Equal("21", f(-5, 8, 7, -1, 7)) +func TestPartialFunc10(t *testing.T) { + type myInt1 int + type myInt2 int + type myInt3 int + type myInt4 int + type myInt5 int + type myInt6 int + type myInt7 int + type myInt8 int + type myInt9 int + type myInt10 int + + add := MFunc10(func(a myInt1, b myInt2, c myInt3, d myInt4, e myInt5, f myInt6, g myInt7, h myInt8, i myInt9, j myInt10) int { + return int(a) + int(b) + int(c) + int(d) + int(e) + int(f) + int(g) + int(h) + int(i) + int(j) + }) + assert.Equal(t, + 55, + add. + Partial(1). + Partial(2). + Partial(3). + Partial(4). + Partial(5). + Partial(6). + Partial(7). + Partial(8). + Partial(9). + Partial(10)()) + assert.Equal(t, + 55, + add. + PartialR(1). + PartialR(2). + PartialR(3). + PartialR(4). + PartialR(5). + PartialR(6). + PartialR(7). + PartialR(8). + PartialR(9). + PartialR(10)()) }