Skip to content

Instantly share code, notes, and snippets.

@logicalguess
Last active January 2, 2020 12:35
Show Gist options
  • Save logicalguess/7fac5b30567b72f590813b2f55914c0f to your computer and use it in GitHub Desktop.
Save logicalguess/7fac5b30567b72f590813b2f55914c0f to your computer and use it in GitHub Desktop.
Function currying in Go.
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