mirror of
https://github.com/duke-git/lancet.git
synced 2026-03-01 00:35:28 +08:00
feat: add function package for funcational programming
This commit is contained in:
72
function/function.go
Normal file
72
function/function.go
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
|
||||||
|
// Use of this source code is governed by MIT license
|
||||||
|
|
||||||
|
// Package function implements some functions for functional programming.
|
||||||
|
|
||||||
|
package function
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// After creates a function that invokes func once it's called n or more times
|
||||||
|
func After(n int, fn interface{}) func(args ...interface{}) []reflect.Value {
|
||||||
|
return func(args ...interface{}) []reflect.Value {
|
||||||
|
n--
|
||||||
|
if n < 1 {
|
||||||
|
return invokeFunc(fn, args...)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Before creates a function that invokes func once it's called less than n times
|
||||||
|
func Before(n int, fn interface{}) func(args ...interface{}) []reflect.Value {
|
||||||
|
var res []reflect.Value
|
||||||
|
|
||||||
|
return func(args ...interface{}) []reflect.Value {
|
||||||
|
if n > 0 {
|
||||||
|
res = invokeFunc(fn, args...)
|
||||||
|
}
|
||||||
|
if n <= 0 {
|
||||||
|
fn = nil
|
||||||
|
}
|
||||||
|
n--
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Fn func(...interface{}) interface{}
|
||||||
|
|
||||||
|
// Curry make a curryed function
|
||||||
|
func (f Fn) Curry(i interface{}) func(...interface{}) interface{} {
|
||||||
|
return func(values ...interface{}) interface{} {
|
||||||
|
v := append([]interface{}{i}, values...)
|
||||||
|
return f(v...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delay make the function excution after delayed time
|
||||||
|
func Delay(delay time.Duration, fn interface{}, args ...interface{}) {
|
||||||
|
time.Sleep(delay)
|
||||||
|
invokeFunc(fn, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Schedule invoke function every duration time, util close the returned bool chan
|
||||||
|
func Schedule(d time.Duration, fn interface{}, args ...interface{}) chan bool {
|
||||||
|
quit := make(chan bool)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
invokeFunc(fn, args...)
|
||||||
|
select {
|
||||||
|
case <-time.After(d):
|
||||||
|
case <-quit:
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
return quit
|
||||||
|
}
|
||||||
95
function/function_test.go
Normal file
95
function/function_test.go
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
package function
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAfter(t *testing.T) {
|
||||||
|
arr := []string{"a", "b"}
|
||||||
|
f := After(len(arr), func(i int) int {
|
||||||
|
fmt.Println("print done")
|
||||||
|
return i
|
||||||
|
})
|
||||||
|
type cb func(args ...interface{}) []reflect.Value
|
||||||
|
print := func(i int, s string, fn cb) {
|
||||||
|
fmt.Printf("print: arr[%d] is %s \n", i, s)
|
||||||
|
v := fn(i)
|
||||||
|
if v != nil {
|
||||||
|
vv := v[0].Int()
|
||||||
|
if vv != 1 {
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fmt.Println("print: arr is", arr)
|
||||||
|
for i := 0; i < len(arr); i++ {
|
||||||
|
print(i, arr[i], f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBefore(t *testing.T) {
|
||||||
|
arr := []string{"a", "b", "c", "d", "e"}
|
||||||
|
f := Before(3, func(i int) int {
|
||||||
|
return i
|
||||||
|
})
|
||||||
|
|
||||||
|
var res []int64
|
||||||
|
type cb func(args ...interface{}) []reflect.Value
|
||||||
|
appendStr := func(i int, s string, fn cb) {
|
||||||
|
fmt.Printf("appendStr: arr[%d] is %s \n", i, s)
|
||||||
|
v := fn(i)
|
||||||
|
res = append(res, v[0].Int())
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < len(arr); i++ {
|
||||||
|
appendStr(i, arr[i], f)
|
||||||
|
}
|
||||||
|
|
||||||
|
expect := []int64{0, 1, 2, 2, 2}
|
||||||
|
if !reflect.DeepEqual(expect, res) {
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCurry(t *testing.T) {
|
||||||
|
add := func(a, b int) int {
|
||||||
|
return a + b
|
||||||
|
}
|
||||||
|
var addCurry Fn = func(values ...interface{}) interface{} {
|
||||||
|
return add(values[0].(int), values[1].(int))
|
||||||
|
}
|
||||||
|
|
||||||
|
add1 := addCurry.Curry(1)
|
||||||
|
v := add1(2)
|
||||||
|
if v != 3 {
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDelay(t *testing.T) {
|
||||||
|
var print = func(s string) {
|
||||||
|
fmt.Println(s)
|
||||||
|
}
|
||||||
|
Delay(2*time.Second, print, "test delay")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSchedule(t *testing.T) {
|
||||||
|
var res []string
|
||||||
|
appendStr := func(s string) {
|
||||||
|
fmt.Println(s)
|
||||||
|
res = append(res, s)
|
||||||
|
}
|
||||||
|
|
||||||
|
stop := Schedule(1*time.Second, appendStr, "*")
|
||||||
|
time.Sleep(5 * time.Second)
|
||||||
|
close(stop)
|
||||||
|
|
||||||
|
expect := []string{"*", "*", "*", "*", "*"}
|
||||||
|
if !reflect.DeepEqual(expect, res) {
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
fmt.Println("done")
|
||||||
|
}
|
||||||
23
function/function_util.go
Normal file
23
function/function_util.go
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
package function
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
)
|
||||||
|
|
||||||
|
func invokeFunc(fn interface{}, args ...interface{}) []reflect.Value {
|
||||||
|
fv := functionValue(fn)
|
||||||
|
params := make([]reflect.Value, len(args))
|
||||||
|
for i, item := range args {
|
||||||
|
params[i] = reflect.ValueOf(item)
|
||||||
|
}
|
||||||
|
return fv.Call(params)
|
||||||
|
}
|
||||||
|
|
||||||
|
func functionValue(function interface{}) reflect.Value {
|
||||||
|
v := reflect.ValueOf(function)
|
||||||
|
if v.Kind() != reflect.Func {
|
||||||
|
panic(fmt.Sprintf("Invalid function type, value of type %T", function))
|
||||||
|
}
|
||||||
|
return v
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user