Reverse slice in go using CPS with generics.
authorsgf <sgf.dma@gmail.com>
Mon, 26 Aug 2024 17:45:47 +0000 (20:45 +0300)
committersgf <sgf.dma@gmail.com>
Mon, 26 Aug 2024 17:45:47 +0000 (20:45 +0300)
revCps/rev.go
revCps/revGen.go [new file with mode: 0644]

index 5818c45..d602ccc 100644 (file)
@@ -3,7 +3,7 @@ package main
 
 import "fmt"
 
-// Haskell: data R a = R (R a) | E {unE :: a}
+// Haskell: data R a = R (R a) | E a
 type R func() (R, []int)
 
 // Haskell: Cont (R [a]) [a]
@@ -25,10 +25,10 @@ func step(x int, xs []int, k Cont) (R, []int) {
 // Haskell: In fact, this is '>>= \zs -> shift (f zs)' in foldr, which is
 // hidden behind 'm'. For reference, haskell shift implementation:
 // shift :: ((a -> r) -> Cont r r) -> Cont r a
-// shift f = Cont $ \k -> runCont (f k) id
+// shift g = Cont $ \k -> runCont (g k) id
 func shift(f func([]int, Cont) (R, []int), k Cont) Cont {
     return func (xs []int) (R, []int) {
-        return f(xs, k)   // Haskell's shift: runCont (f k) id
+        return f(xs, k)   // Haskell's shift: runCont (g k) id
     }
 }
 
@@ -53,8 +53,8 @@ func reverseCps(xs0 []int) (R, []int) {
     return nil, []int{} // return . E
 }
 
-func getResult(f R, zs []int) []int {
-    for ; zs == nil; f, zs = f() {    // Haskell: fix run
+func runR(f R, zs []int) []int {
+    for ; f != nil; f, zs = f() {    // Haskell: fix run
         fmt.Printf("Iterate..\n")
     }
     return zs
@@ -62,6 +62,6 @@ func getResult(f R, zs []int) []int {
 
 func main() {
     xs := []int{1, 2, 3, 4}
-    fmt.Printf("%v\n", getResult(reverseCps(xs)))
+    fmt.Printf("%v\n", runR(reverseCps(xs)))
 }
 
diff --git a/revCps/revGen.go b/revCps/revGen.go
new file mode 100644 (file)
index 0000000..0367609
--- /dev/null
@@ -0,0 +1,69 @@
+
+package main
+
+import "fmt"
+
+// Haskell: data R a = R (R a) | E a
+type R [Result any] func() (R[Result], Result)
+
+// Haskell: Cont (R Result) T
+type Cont [T any, Result any] func(T) (R[Result], Result)
+
+// Type of function in shift, just a shortcut. See note below about this
+// 'shift' and Haskell's 'shift' differences.
+type shiftFunc [T any, Result any] func(T, Cont[T, Result]) (R[Result], Result)
+
+// Haskell: In fact, this is '>>= \zs -> shift (f zs)' in foldr, which is
+// hidden behind 'm'. For reference, haskell shift implementation:
+// shift :: ((a -> r) -> Cont r r) -> Cont r a
+// shift g = Cont $ \k -> runCont (g k) id
+func shift[T any, Result any](f shiftFunc[T, Result], k Cont[T, Result]) Cont[T, Result] {
+    return func (xs T) (R[Result], Result) {
+        return f(xs, k)   // Haskell's shift: runCont (g k) id
+    }
+}
+
+func runR[Result any](f R[Result], zs Result) Result {
+    for ; f != nil; f, zs = f() {    // Haskell: fix run
+        fmt.Printf("Iterate..\n")
+    }
+    return zs
+}
+
+// step builds reverse slice in xs, but the final result is string
+// representation of reverse slice. Well, this is just for more easily
+// distinguishing result type from type passed along the monadic chain.
+func step(x int, xs []int, k Cont[[]int, string]) (R[string], string) {
+    fmt.Printf("Got x = %v, xs = %v, k = %v\n", x, xs, k)
+    xs = append(xs, x)
+    if k != nil {   // Preserve nil.
+        // Haskell: R (k (x : xs))
+        t := func() (R[string], string) { // t is thunk.
+            return k(xs)
+        }
+        return t, ""
+    }
+    return nil, fmt.Sprintf("%v", xs)
+}
+
+func reverseCps(xs0 []int) (R[string], string) {
+    // Build reverse slice into slice in monadic chain, but return result as a
+    // its string representation.
+    var m Cont[[]int, string]  // Haskell: Cont (R [a]) [a]
+    for _, x := range xs0 { // Haskell: foldr .. xs
+        stepX := func (xs []int, k Cont[[]int, string]) (R[string], string) { return step(x, xs, k) } // Haskell: step x
+        m = shift(stepX, m) // Haskell: \zs -> m =<< (shift (step x zs))
+    }
+
+    if m != nil {
+        // Unwrap Cont.
+        return m(nil)   // flip runCont id
+    }
+    return nil, "" // return . E
+}
+
+func main() {
+    xs := []int{1, 2, 3, 4}
+    fmt.Printf("%v\n", runR(reverseCps(xs)))
+}
+