From: sgf Date: Thu, 1 Jun 2023 18:24:50 +0000 (+0300) Subject: Check several values in map and query, if missed, using continuations. X-Git-Url: https://gitweb.sgf-dma.tk/?a=commitdiff_plain;h=7bd9174f62d17037990df46043658e728e05bc30;p=go.git Check several values in map and query, if missed, using continuations. --- diff --git a/cont.go b/cont.go new file mode 100644 index 0000000..ece24a0 --- /dev/null +++ b/cont.go @@ -0,0 +1,206 @@ + +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() +} +