mirror of
https://github.com/IBM/fp-go.git
synced 2025-08-10 22:31:32 +02:00
fix: generate sequenceT
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
This commit is contained in:
203
cli/apply.go
Normal file
203
cli/apply.go
Normal file
@@ -0,0 +1,203 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
C "github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
func generateSequenceT(f *os.File, i int) {
|
||||
fmt.Fprintf(f, "\n// SequenceT%d is a utility function used to implement the sequence operation for higher kinded types based only on map and ap.\n", i)
|
||||
fmt.Fprintf(f, "// The function takes %d higher higher kinded types and returns a higher kinded type of a [Tuple%d] with the resolved values.\n", i, i)
|
||||
fmt.Fprintf(f, "func SequenceT%d[\n", i)
|
||||
// map as the starting point
|
||||
fmt.Fprintf(f, " MAP ~func(HKT_T1,")
|
||||
for j := 0; j < i; j++ {
|
||||
fmt.Fprintf(f, " func(T%d)", j+1)
|
||||
}
|
||||
fmt.Fprintf(f, " ")
|
||||
fmt.Fprintf(f, "T.")
|
||||
writeTupleType(f, i)
|
||||
fmt.Fprintf(f, ")")
|
||||
if i > 1 {
|
||||
fmt.Fprintf(f, " HKT_F")
|
||||
for k := 1; k < i; k++ {
|
||||
fmt.Fprintf(f, "_T%d", k+1)
|
||||
}
|
||||
} else {
|
||||
fmt.Fprintf(f, " HKT_TUPLE%d", i)
|
||||
}
|
||||
fmt.Fprintf(f, ",\n")
|
||||
// the applicatives
|
||||
for j := 1; j < i; j++ {
|
||||
fmt.Fprintf(f, " AP%d ~func(", j)
|
||||
fmt.Fprintf(f, "HKT_F")
|
||||
for k := j; k < i; k++ {
|
||||
fmt.Fprintf(f, "_T%d", k+1)
|
||||
}
|
||||
fmt.Fprintf(f, ", HKT_T%d)", j+1)
|
||||
if j+1 < i {
|
||||
fmt.Fprintf(f, " HKT_F")
|
||||
for k := j + 1; k < i; k++ {
|
||||
fmt.Fprintf(f, "_T%d", k+1)
|
||||
}
|
||||
} else {
|
||||
fmt.Fprintf(f, " HKT_TUPLE%d", i)
|
||||
}
|
||||
fmt.Fprintf(f, ",\n")
|
||||
}
|
||||
|
||||
for j := 0; j < i; j++ {
|
||||
fmt.Fprintf(f, " T%d,\n", j+1)
|
||||
}
|
||||
for j := 0; j < i; j++ {
|
||||
fmt.Fprintf(f, " HKT_T%d, // HKT[T%d]\n", j+1, j+1)
|
||||
}
|
||||
for j := 1; j < i; j++ {
|
||||
fmt.Fprintf(f, " HKT_F")
|
||||
for k := j; k < i; k++ {
|
||||
fmt.Fprintf(f, "_T%d", k+1)
|
||||
}
|
||||
fmt.Fprintf(f, ", // HKT[")
|
||||
for k := j; k < i; k++ {
|
||||
fmt.Fprintf(f, "func(T%d) ", k+1)
|
||||
}
|
||||
fmt.Fprintf(f, "T.")
|
||||
writeTupleType(f, i)
|
||||
fmt.Fprintf(f, "]\n")
|
||||
}
|
||||
fmt.Fprintf(f, " HKT_TUPLE%d any, // HKT[", i)
|
||||
writeTupleType(f, i)
|
||||
fmt.Fprintf(f, "]\n")
|
||||
fmt.Fprintf(f, "](\n")
|
||||
|
||||
// the callbacks
|
||||
fmt.Fprintf(f, " fmap MAP,\n")
|
||||
for j := 1; j < i; j++ {
|
||||
fmt.Fprintf(f, " fap%d AP%d,\n", j, j)
|
||||
}
|
||||
// the parameters
|
||||
for j := 0; j < i; j++ {
|
||||
fmt.Fprintf(f, " t%d HKT_T%d,\n", j+1, j+1)
|
||||
}
|
||||
fmt.Fprintf(f, ") HKT_TUPLE%d {\n", i)
|
||||
|
||||
fmt.Fprintf(f, " return ")
|
||||
|
||||
for j := i - 1; j >= 1; j-- {
|
||||
fmt.Fprintf(f, "fap%d(", j)
|
||||
}
|
||||
fmt.Fprintf(f, "fmap(t1, tupleConstructor%d[", i)
|
||||
for j := 0; j < i; j++ {
|
||||
if j > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "T%d", j+1)
|
||||
}
|
||||
fmt.Fprintf(f, "]())")
|
||||
for j := 1; j < i; j++ {
|
||||
fmt.Fprintf(f, ", t%d)", j+1)
|
||||
}
|
||||
fmt.Fprintf(f, "\n")
|
||||
|
||||
fmt.Fprintf(f, "}\n")
|
||||
}
|
||||
|
||||
func generateTupleConstructor(f *os.File, i int) {
|
||||
// Create the optionize version
|
||||
fmt.Fprintf(f, "\n// tupleConstructor%d returns a curried version of [T.MakeTuple%d]\n", i, i)
|
||||
fmt.Fprintf(f, "func tupleConstructor%d[", i)
|
||||
for j := 0; j < i; j++ {
|
||||
if j > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "T%d", j+1)
|
||||
}
|
||||
fmt.Fprintf(f, " any]()")
|
||||
for j := 0; j < i; j++ {
|
||||
fmt.Fprintf(f, " func(T%d)", j+1)
|
||||
}
|
||||
fmt.Fprintf(f, " T.Tuple%d[", i)
|
||||
for j := 0; j < i; j++ {
|
||||
if j > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "T%d", j+1)
|
||||
}
|
||||
fmt.Fprintf(f, "] {\n")
|
||||
|
||||
fmt.Fprintf(f, " return F.Curry%d(T.MakeTuple%d[", i, i)
|
||||
for j := 0; j < i; j++ {
|
||||
if j > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "T%d", j+1)
|
||||
}
|
||||
fmt.Fprintf(f, "])\n")
|
||||
|
||||
fmt.Fprintf(f, "}\n")
|
||||
}
|
||||
|
||||
func generateApplyHelpers(filename string, count int) error {
|
||||
dir, err := os.Getwd()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
absDir, err := filepath.Abs(dir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
pkg := filepath.Base(absDir)
|
||||
f, err := os.Create(filepath.Clean(filename))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
// log
|
||||
log.Printf("Generating code in [%s] for package [%s] with [%d] repetitions ...", filename, pkg, count)
|
||||
|
||||
// some header
|
||||
fmt.Fprintln(f, "// Code generated by go generate; DO NOT EDIT.")
|
||||
fmt.Fprintln(f, "// This file was generated by robots at")
|
||||
fmt.Fprintf(f, "// %s\n", time.Now())
|
||||
|
||||
fmt.Fprintf(f, "package %s\n\n", pkg)
|
||||
|
||||
// print out some helpers
|
||||
fmt.Fprintf(f, `
|
||||
import (
|
||||
F "github.com/ibm/fp-go/function"
|
||||
T "github.com/ibm/fp-go/tuple"
|
||||
)
|
||||
`)
|
||||
|
||||
for i := 1; i <= count; i++ {
|
||||
// tuple constructor
|
||||
generateTupleConstructor(f, i)
|
||||
// sequenceT
|
||||
generateSequenceT(f, i)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func ApplyCommand() *C.Command {
|
||||
return &C.Command{
|
||||
Name: "apply",
|
||||
Usage: "generate code for the sequence operations of apply",
|
||||
Flags: []C.Flag{
|
||||
flagCount,
|
||||
flagFilename,
|
||||
},
|
||||
Action: func(ctx *C.Context) error {
|
||||
return generateApplyHelpers(
|
||||
ctx.String(keyFilename),
|
||||
ctx.Int(keyCount),
|
||||
)
|
||||
},
|
||||
}
|
||||
}
|
279
cli/bind.go
Normal file
279
cli/bind.go
Normal file
@@ -0,0 +1,279 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
C "github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
func createCombinations(n int, all, prev []int) [][]int {
|
||||
l := len(prev)
|
||||
if l == n {
|
||||
return [][]int{prev}
|
||||
}
|
||||
var res [][]int
|
||||
for idx, val := range all {
|
||||
cpy := make([]int, l+1)
|
||||
copy(cpy, prev)
|
||||
cpy[l] = val
|
||||
|
||||
res = append(res, createCombinations(n, all[idx+1:], cpy)...)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func remaining(comb []int, total int) []int {
|
||||
var res []int
|
||||
mp := make(map[int]int)
|
||||
for _, idx := range comb {
|
||||
mp[idx] = idx
|
||||
}
|
||||
for i := 1; i <= total; i++ {
|
||||
_, ok := mp[i]
|
||||
if !ok {
|
||||
res = append(res, i)
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func generateCombSingleBind(f *os.File, comb [][]int, total int) {
|
||||
for _, c := range comb {
|
||||
// remaining indexes
|
||||
rem := remaining(c, total)
|
||||
|
||||
// bind function
|
||||
fmt.Fprintf(f, "\n// Bind")
|
||||
for _, idx := range c {
|
||||
fmt.Fprintf(f, "%d", idx)
|
||||
}
|
||||
fmt.Fprintf(f, "of%d takes a function with %d parameters and returns a new function with %d parameters that will bind these parameters to the positions [", total, total, len(c))
|
||||
for i, idx := range c {
|
||||
if i > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "%d", idx)
|
||||
}
|
||||
fmt.Fprintf(f, "] of the original function.\n// The return value of is a function with the remaining %d parameters at positions [", len(rem))
|
||||
for i, idx := range rem {
|
||||
if i > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "%d", idx)
|
||||
}
|
||||
fmt.Fprintf(f, "] of the original function.\n")
|
||||
fmt.Fprintf(f, "func Bind")
|
||||
for _, idx := range c {
|
||||
fmt.Fprintf(f, "%d", idx)
|
||||
}
|
||||
fmt.Fprintf(f, "of%d[F ~func(", total)
|
||||
for i := 0; i < total; i++ {
|
||||
if i > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "T%d", i+1)
|
||||
}
|
||||
fmt.Fprintf(f, ") R")
|
||||
for i := 0; i < total; i++ {
|
||||
fmt.Fprintf(f, ", T%d", i+1)
|
||||
}
|
||||
fmt.Fprintf(f, ", R any](f F) func(")
|
||||
for i, idx := range c {
|
||||
if i > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "T%d", idx)
|
||||
}
|
||||
fmt.Fprintf(f, ") func(")
|
||||
for i, idx := range rem {
|
||||
if i > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "T%d", idx)
|
||||
}
|
||||
fmt.Fprintf(f, ") R {\n")
|
||||
|
||||
fmt.Fprintf(f, " return func(")
|
||||
|
||||
for i, idx := range c {
|
||||
if i > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "t%d T%d", idx, idx)
|
||||
}
|
||||
fmt.Fprintf(f, ") func(")
|
||||
for i, idx := range rem {
|
||||
if i > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "T%d", idx)
|
||||
}
|
||||
fmt.Fprintf(f, ") R {\n")
|
||||
|
||||
fmt.Fprintf(f, " return func(")
|
||||
for i, idx := range rem {
|
||||
if i > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "t%d T%d", idx, idx)
|
||||
}
|
||||
fmt.Fprintf(f, ") R {\n")
|
||||
|
||||
fmt.Fprintf(f, " return f(")
|
||||
for i := 1; i <= total; i++ {
|
||||
if i > 1 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "t%d", i)
|
||||
}
|
||||
fmt.Fprintf(f, ")\n")
|
||||
|
||||
fmt.Fprintf(f, " }\n")
|
||||
fmt.Fprintf(f, " }\n")
|
||||
fmt.Fprintf(f, "}\n")
|
||||
|
||||
// ignore function
|
||||
fmt.Fprintf(f, "\n// Ignore")
|
||||
for _, idx := range c {
|
||||
fmt.Fprintf(f, "%d", idx)
|
||||
}
|
||||
fmt.Fprintf(f, "of%d takes a function with %d parameters and returns a new function with %d parameters that will ignore the values at positions [", total, len(rem), total)
|
||||
for i, idx := range c {
|
||||
if i > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "%d", idx)
|
||||
}
|
||||
fmt.Fprintf(f, "] and pass the remaining %d parameters to the original function\n", len(rem))
|
||||
fmt.Fprintf(f, "func Ignore")
|
||||
for _, idx := range c {
|
||||
fmt.Fprintf(f, "%d", idx)
|
||||
}
|
||||
fmt.Fprintf(f, "of%d[", total)
|
||||
// start with the undefined parameters
|
||||
for i, idx := range c {
|
||||
if i > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "T%d", idx)
|
||||
}
|
||||
if len(c) > 0 {
|
||||
fmt.Fprintf(f, " any, ")
|
||||
}
|
||||
fmt.Fprintf(f, "F ~func(")
|
||||
for i, idx := range rem {
|
||||
if i > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "T%d", idx)
|
||||
}
|
||||
fmt.Fprintf(f, ") R")
|
||||
for _, idx := range rem {
|
||||
fmt.Fprintf(f, ", T%d", idx)
|
||||
}
|
||||
fmt.Fprintf(f, ", R any](f F) func(")
|
||||
for i := 0; i < total; i++ {
|
||||
if i > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "T%d", i+1)
|
||||
}
|
||||
fmt.Fprintf(f, ") R {\n")
|
||||
|
||||
fmt.Fprintf(f, " return func(")
|
||||
for i := 0; i < total; i++ {
|
||||
if i > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "t%d T%d", i+1, i+1)
|
||||
}
|
||||
fmt.Fprintf(f, ") R {\n")
|
||||
fmt.Fprintf(f, " return f(")
|
||||
for i, idx := range rem {
|
||||
if i > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "t%d", idx)
|
||||
}
|
||||
fmt.Fprintf(f, ")\n")
|
||||
|
||||
fmt.Fprintf(f, " }\n")
|
||||
fmt.Fprintf(f, "}\n")
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func generateSingleBind(f *os.File, total int) {
|
||||
|
||||
fmt.Fprintf(f, "// Combinations for a total of %d arguments\n", total)
|
||||
|
||||
// construct the indexes
|
||||
all := make([]int, total)
|
||||
for i := 0; i < total; i++ {
|
||||
all[i] = i + 1
|
||||
}
|
||||
// for all permutations of a certain length
|
||||
for j := 0; j < total; j++ {
|
||||
// get combinations of that size
|
||||
comb := createCombinations(j+1, all, []int{})
|
||||
generateCombSingleBind(f, comb, total)
|
||||
}
|
||||
}
|
||||
|
||||
func generateBind(f *os.File, i int) {
|
||||
for j := 1; j < i; j++ {
|
||||
generateSingleBind(f, j)
|
||||
}
|
||||
}
|
||||
|
||||
func generateBindHelpers(filename string, count int) error {
|
||||
dir, err := os.Getwd()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
absDir, err := filepath.Abs(dir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
pkg := filepath.Base(absDir)
|
||||
f, err := os.Create(filepath.Clean(filename))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
// log
|
||||
log.Printf("Generating code in [%s] for package [%s] with [%d] repetitions ...", filename, pkg, count)
|
||||
|
||||
// some header
|
||||
fmt.Fprintln(f, "// Code generated by go generate; DO NOT EDIT.")
|
||||
fmt.Fprintln(f, "// This file was generated by robots at")
|
||||
fmt.Fprintf(f, "// %s\n", time.Now())
|
||||
|
||||
fmt.Fprintf(f, "package %s\n", pkg)
|
||||
|
||||
generateBind(f, count)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func BindCommand() *C.Command {
|
||||
return &C.Command{
|
||||
Name: "bind",
|
||||
Usage: "generate code for binder functions etc",
|
||||
Description: "Code generation for bind, etc",
|
||||
Flags: []C.Flag{
|
||||
flagCount,
|
||||
flagFilename,
|
||||
},
|
||||
Action: func(ctx *C.Context) error {
|
||||
return generateBindHelpers(
|
||||
ctx.String(keyFilename),
|
||||
ctx.Int(keyCount),
|
||||
)
|
||||
},
|
||||
}
|
||||
}
|
@@ -10,5 +10,7 @@ func Commands() []*C.Command {
|
||||
OptionCommand(),
|
||||
EitherCommand(),
|
||||
TupleCommand(),
|
||||
BindCommand(),
|
||||
ApplyCommand(),
|
||||
}
|
||||
}
|
||||
|
@@ -106,7 +106,7 @@ func generateEitherHelpers(filename string, count int) error {
|
||||
return err
|
||||
}
|
||||
pkg := filepath.Base(absDir)
|
||||
f, err := os.Create(filename)
|
||||
f, err := os.Create(filepath.Clean(filename))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@@ -106,7 +106,7 @@ func generateOptionHelpers(filename string, count int) error {
|
||||
return err
|
||||
}
|
||||
pkg := filepath.Base(absDir)
|
||||
f, err := os.Create(filename)
|
||||
f, err := os.Create(filepath.Clean(filename))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@@ -311,7 +311,7 @@ func generatePipeHelpers(filename string, count int) error {
|
||||
return err
|
||||
}
|
||||
pkg := filepath.Base(absDir)
|
||||
f, err := os.Create(filename)
|
||||
f, err := os.Create(filepath.Clean(filename))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@@ -262,7 +262,7 @@ func generateTupleHelpers(filename string, count int) error {
|
||||
return err
|
||||
}
|
||||
pkg := filepath.Base(absDir)
|
||||
f, err := os.Create(filename)
|
||||
f, err := os.Create(filepath.Clean(filename))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
Reference in New Issue
Block a user