--- /dev/null
+
+package main
+
+import (
+ "fmt"
+)
+
+// - Function fillMap() fills the map.
+// - And fillMap() should run only once for continuation chain.
+//
+// - Function h() checks the value x in the map. If it's missed, it tries to
+// call fillMap() (if it wasn't already called) and checks the value again.
+// - If h() finds the value (either at first or second try) it calls the next
+// step.
+
+var m1 map[int]string
+var queried1 bool
+
+func fillMap1() {
+ fmt.Printf("Filling map1\n")
+ queried1 = true
+ if m1 == nil {
+ m1 = make(map[int]string)
+ }
+ m1[1] = "111"
+ m1[2] = "222"
+ m1[3] = "333"
+}
+
+type Q func() (Q, error)
+
+// Use global 'queried1' state.
+func h1(x int, k Q) (Q, error) {
+ z, ok := m1[x]
+ if !ok {
+ fmt.Printf("h(%v): Missed key %v. Refill map.\n", x, x)
+ if queried1 {
+ return nil, fmt.Errorf("h(%v): No such key %v", x, x)
+ }
+ fillMap1()
+ return func() (Q, error) { return h1(x, k) }, nil
+ }
+ fmt.Printf("h(%v): Obtained %v\n", x, z)
+ return k, nil
+}
+
+func run1() {
+ var err error
+
+ fmt.Printf("========== Start1\n")
+
+ g3 := func () (Q, error) { return h1(3, nil) }
+ g2 := func () (Q, error) { return h1(2, g3) }
+ g1 := func () (Q, error) { return h1(1, g2) }
+ fmt.Printf("g1 = %v, g2 = %v, g3 = %v\n", g1, g2, g3)
+ k := g1
+ for k != nil {
+ fmt.Printf("Calling %v\n", k)
+ k, err = k()
+ if err != nil {
+ fmt.Printf("Received error: %v\n", err)
+ break
+ }
+ }
+ fmt.Printf("End1\n")
+}
+
+
+var m2 map[int]string
+
+func fillMap2() {
+ fmt.Printf("Filling map2\n")
+ if m2 == nil {
+ m2 = make(map[int]string)
+ }
+ m2[1] = "111"
+ m2[2] = "222"
+ m2[3] = "333"
+}
+
+// Pass "queried" state internally inside continuations chain.
+func h2(x int, k func(bool) Q, queried bool) (Q, error) {
+ z, ok := m2[x]
+ if !ok {
+ fmt.Printf("h(%v): Missed key %v.\n", x, x)
+ if queried {
+ return nil, fmt.Errorf("h(%v): No such key %v", x, x)
+ }
+ fmt.Printf("h(%v): Refill map.\n", x)
+ fillMap2()
+ fmt.Printf("h(%v): Retry.\n", x)
+ return func() (Q, error) { return h2(x, k, true) }, nil
+ }
+ fmt.Printf("h(%v): Obtained %v. Continue to next step.\n", x, z)
+ var c Q
+ if k != nil {
+ c = k(queried)
+ }
+ return c, nil
+}
+
+func run2() {
+ var err error
+
+ fmt.Printf("========== Start2\n")
+
+ // Steps in reverse order. Execution order g1 -> g2 -> g3.
+ g3 := func (q bool) Q { return func () (Q, error) { return h2(3, nil, q) } }
+ g2 := func (q bool) Q { return func () (Q, error) { return h2(2, g3, q) } }
+ g1 := func () (Q, error) { return h2(1, g2, false) }
+ k := g1
+ for k != nil {
+ k, err = k()
+ if err != nil {
+ fmt.Printf("Received error: %v\n", err)
+ break
+ }
+ }
+ fmt.Printf("End2\n")
+}
+
+
+var m3 map[int]string
+
+func fillMap3() {
+ fmt.Printf("Filling map3\n")
+ if m3 == nil {
+ m3 = make(map[int]string)
+ }
+ m3[1] = "111"
+ m3[2] = "222"
+ m3[3] = "333"
+}
+
+// Add names to each continuation for pretty printing.
+type Q3 func() (Cont, error)
+
+type Cont struct {
+ name string
+ k Q3
+}
+
+func (c Cont) String() string {
+ return fmt.Sprintf("Cont{%v}", c.name)
+}
+
+func (c Cont) h3(x int, k func(bool) Cont, queried bool) (Cont, error) {
+ z, ok := m3[x]
+ if !ok {
+ fmt.Printf("[%v] h(%v): Missed key %v.\n", c, x, x)
+ if queried {
+ return Cont{k: nil}, fmt.Errorf("[%v] h(%v): No such key %v", c, x, x)
+ }
+ fmt.Printf("[%v] h(%v): Refill map.\n", c, x)
+ fillMap3()
+ fmt.Printf("[%v] h(%v): Retry.\n", c, x)
+ c.k = func() (Cont, error) { return c.h3(x, k, true) }
+ return c, nil
+ }
+ fmt.Printf("[%v] h(%v): Obtained %v.\n", c, x, z)
+ var next Cont
+ if k != nil {
+ next = k(queried)
+ }
+ fmt.Printf("[%v] h(%v): Continue to %v.\n", c, x, next)
+ return next, nil
+}
+
+func run3() {
+ var err error
+
+ fmt.Printf("========== Start3\n")
+
+ c3 := Cont{name: "c3"}
+ g3 := func (q bool) Cont {
+ c3.k = func () (Cont, error) { return c3.h3(3, nil, q) }
+ return c3
+ }
+
+ c2 := Cont{name: "c2"}
+ g2 := func (q bool) Cont {
+ c2.k = func () (Cont, error) { return c2.h3(2, g3, q) }
+ return c2
+ }
+
+ c1 := Cont{name: "c1"}
+ c1.k = func () (Cont, error) { return c1.h3(1, g2, false) }
+
+ c := c1
+ for c.k != nil {
+ fmt.Printf("Calling %v\n", c)
+ c, err = c.k()
+ if err != nil {
+ fmt.Printf("Received error: %v\n", err)
+ break
+ }
+ }
+ fmt.Printf("End3\n")
+}
+
+func main() {
+ run1()
+ run2()
+ run3()
+}
+