Skip to content

Instantly share code, notes, and snippets.

@lisp-ceo
Created October 8, 2019 03:11
Show Gist options
  • Save lisp-ceo/cd41499ae25235088eb78f21e2ef5f58 to your computer and use it in GitHub Desktop.
Save lisp-ceo/cd41499ae25235088eb78f21e2ef5f58 to your computer and use it in GitHub Desktop.
Calling variadric validation functions *with* type safety
package main
import (
"fmt"
)
type Approval struct {
Name string
Predicate func(...interface{}) error
// WrapperFn // TODO no way to specify multiple types!
}
type IPredicate interface {
Approval(...interface{}) error // no way to compare
}
func main() {
costLowerThanLimit := func(args ...interface{}) error {
cost := args[0].(int)
limit := args[1].(int)
if cost <= limit {
return nil
}
return fmt.Errorf("cost is more than allowed ($%d > $%d)", cost, limit)
}
noZeroDollarConsignments := func(args ...interface{}) error {
cost := args[0].(int)
floor := 0
if cost >= floor {
return nil
}
return fmt.Errorf("cost is lower than allowed ($%d < $%d)", cost, floor)
}
t := Approval{
Name: "User can consign over $5",
Predicate: costLowerThanLimit,
}
t2 := Approval{
Name: "User must consign over $0",
Predicate: noZeroDollarConsignments,
}
fmt.Printf("%#v\n", t)
e := t.Predicate(10, 5)
fmt.Printf("%#v\n", e)
o := t.Predicate(5, 10)
fmt.Printf("%#v\n", o)
c := func(cost int, limit int) error {
if cost <= limit {
return nil
}
return fmt.Errorf("cost is more than allowed ($%d > $%d)", cost, limit)
}
var exCast (func(...interface{}) error)
exCast = func(args ...interface{}) error {
cost := args[0].(int)
limit := args[1].(int)
return c(cost, limit)
}
fmt.Printf("%#v\n", exCast(5, 10))
fmt.Printf("%#v\n", exCast(10, 5))
// XXX painful to generate all the combinations of callers for the interface
// how to avoid hand-typing at every call site the cast
// exCaster := func(f (func(...interface{}) error)) (func(...interface{}) error) {
// }
IntWrapper := func(cost int, f func(args ...interface{}) error) error {
return f(cost)
}
IntIntWrapper := func(cost int, limit int, f func(args ...interface{}) error) error {
return f(cost, limit)
}
isLowerThanLimit := IntIntWrapper(10, 5, costLowerThanLimit)
fmt.Printf("%#v\n", isLowerThanLimit)
isHigherThanFloor := IntWrapper(10, noZeroDollarConsignments)
fmt.Printf("%#v\n", isHigherThanFloor)
approvals := []Approval{
t,
t2,
}
for _, approval := range approvals {
// XXX there is no information here on how to call the predicates
// we can't encode in the type system
fmt.Printf("fuck this: %#v\n", approval)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment