Last active
January 2, 2020 12:35
-
-
Save logicalguess/7fac5b30567b72f590813b2f55914c0f to your computer and use it in GitHub Desktop.
Function currying in Go.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"fmt" | |
"reflect" | |
) | |
type G interface{} | |
type F func(...G) G | |
func (f F) Apply(a G) F { | |
return func(values ...G) G { | |
values = append([]G{a}, values...) | |
return f(values...) | |
} | |
} | |
func Apply(fn G, args ...G) F { | |
var fun = wrap(fn) | |
for _, arg := range args { | |
fun = fun.Apply(arg) | |
} | |
return fun | |
} | |
func ApplyAll(fn G, args ...G) G { | |
fnT := reflect.TypeOf(fn) | |
if fnT.Kind() != reflect.Func { | |
panic(fmt.Errorf("%T must be a function", fn)) | |
} | |
l := len(args) | |
if fnT.NumIn() > l { | |
return Apply(fn, args...) | |
} else | |
if fnT.NumIn() == l { | |
return Apply(fn, args...)() | |
} else { | |
panic(fmt.Errorf("%v arguments are too many for function %T", l, fn)) | |
} | |
} | |
func wrap(fn G) F { | |
return func(a ...G) G{ | |
return invoke(fn, a) | |
} | |
} | |
func invoke(fn G, args []G) G { | |
var vs []reflect.Value | |
for _, arg := range args { | |
vs = append(vs, reflect.ValueOf(arg)) | |
} | |
fun := reflect.ValueOf(fn) | |
return fun.Call(vs)[0].Interface() | |
} | |
func Curry(fn G, args []G) F { | |
var f F = wrap(fn) | |
for _, elem := range args { | |
f = f.Apply(elem) | |
} | |
return f | |
} | |
func sum(a int, b int, c int) int { | |
return a + b + c | |
} | |
func size(a int, b string) int { | |
return a + len(b) | |
} | |
func main() { | |
fmt.Println(wrap(sum).Apply(1)(2, 3)) //6 | |
fmt.Println(wrap(sum).Apply(1).Apply(2)(3)) //6 | |
fmt.Println(wrap(sum).Apply(1).Apply(2).Apply(3)()) //6 | |
fmt.Println(Apply(sum, 1)(2, 3)) //6 | |
fmt.Println(Apply(sum, 1, 2)(3)) //6 | |
fmt.Println(Apply(sum, 1, 2, 3)()) //6 | |
fmt.Println(ApplyAll(sum, 1, 2, 3)) //6 | |
fmt.Println(ApplyAll(sum, 1, 2).(F)(3)) //6 | |
fmt.Println(Apply(Apply(Apply(sum, 3),2),1)()) //6 | |
fmt.Println(Apply(size, 1)("ab")) //3 | |
fmt.Println(Apply(size, 1, "ab")()) //3 | |
fmt.Println(Curry(sum, []G{1})(2, 3)) //6 | |
fmt.Println(Curry(sum, []G{1, 2})(3)) //6 | |
fmt.Println(Curry(sum, []G{1, 2, 3})()) //6 | |
fmt.Println(Curry(size, []G{1})("ab")) //3 | |
fmt.Println(Curry(size, []G{1, "ab"})()) //3 | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment