First class environments: Difference between revisions

Content added Content deleted
No edit summary
(Omit from Go)
Line 159: Line 159:


COUNTS:
COUNTS:
0 1 7 2 5 8 16 3 19 6 14 9
</pre>

=={{header|Go}}==
{{incorrect|Go|The libraries have changed and this example no longer works.}}
Using eval package originally part of Go standard library, now externally hosted and maintained.

Variance: package support is yet incomplete, so the common piece of code has no way to print hv, as requested by the task. Instead, printing is done outside of the common piece of code, by directly inspecting the environments.
<lang go>package main

import (
"bitbucket.org/binet/go-eval/pkg/eval"
"fmt"
"go/parser"
"go/token"
)

type pair struct {
name string
value int
}

type environment struct {
binding map[string]*intV
world *eval.World
}

func newEnvironment(iv []pair) (environment, error) {
e := environment{make(map[string]*intV), eval.NewWorld()}
for _, p := range iv {
v := intV(p.value)
err := e.world.DefineVar(p.name, eval.IntType, &v)
if err != nil {
return environment{}, err
}
e.binding[p.name] = &v
}
return e, nil
}

func main() {
// create 12 environments with intial values
e12 := make([]environment, 12)
var err error
for i := range e12 {
e12[i], err = newEnvironment([]pair{{"hv", i + 1}, {"count", 0}})
if err != nil {
fmt.Println(err)
return
}
}
// define single piece of code.
// the parser returns a list of abstract syntax trees.
fset := token.NewFileSet()
spoc, err := parser.ParseStmtList(fset, "spoc", `
if hv > 1 {
if hv % 2 == 0 {
hv /= 2
} else {
hv = 3*hv + 1
}
count++
}
`)
if err != nil {
fmt.Println(err)
return
}
// iterate until all sequences complete
all:
for {
// check for all sequences complete
for i := 0; *e12[i].binding["hv"] == 1; i++ {
if i == 11 {
break all
}
}
// iterate sequences
for _, e := range e12 {
// output hv in this environment
// (library deficiency that it can't be done in the spoc.)
fmt.Printf(" %3d", *e.binding["hv"])

// bind code,
code, err := e.world.CompileStmtList(fset, spoc)
if err != nil {
fmt.Println(err)
return
}
// evaluate,
_, err = code.Run()
if err != nil {
fmt.Println(err)
return
}
// and abandon the code binding. it's a little wasteful.
// code binding could be done up front, once for each environment,
// and saved in the environment struct. it's repeated here just
// to avoid the question of whether it is still a "single piece
// of code" if it is compiled 12 times and pointers to the 12
// instances are saved.
}
fmt.Println()
}
fmt.Println("Counts:")
for _, e := range e12 {
fmt.Printf(" %3d", *e.binding["count"])
}
fmt.Println()
}

// int value implementation
type intV int

func (v *intV) String() string { return fmt.Sprint(*v) }
func (v *intV) Get(*eval.Thread) int64 { return int64(*v) }
func (v *intV) Set(_ *eval.Thread, x int64) { *v = intV(x) }
func (v *intV) Assign(t *eval.Thread, o eval.Value) {
*v = intV(o.(eval.IntValue).Get(t))
}</lang>
{{out}}
<pre>
1 2 3 4 5 6 7 8 9 10 11 12
1 1 10 2 16 3 22 4 28 5 34 6
1 1 5 1 8 10 11 2 14 16 17 3
1 1 16 1 4 5 34 1 7 8 52 10
1 1 8 1 2 16 17 1 22 4 26 5
1 1 4 1 1 8 52 1 11 2 13 16
1 1 2 1 1 4 26 1 34 1 40 8
1 1 1 1 1 2 13 1 17 1 20 4
1 1 1 1 1 1 40 1 52 1 10 2
1 1 1 1 1 1 20 1 26 1 5 1
1 1 1 1 1 1 10 1 13 1 16 1
1 1 1 1 1 1 5 1 40 1 8 1
1 1 1 1 1 1 16 1 20 1 4 1
1 1 1 1 1 1 8 1 10 1 2 1
1 1 1 1 1 1 4 1 5 1 1 1
1 1 1 1 1 1 2 1 16 1 1 1
1 1 1 1 1 1 1 1 8 1 1 1
1 1 1 1 1 1 1 1 4 1 1 1
1 1 1 1 1 1 1 1 2 1 1 1
Counts:
0 1 7 2 5 8 16 3 19 6 14 9
0 1 7 2 5 8 16 3 19 6 14 9
</pre>
</pre>
Line 759: Line 617:


{{omit from|Ada|Task could be completed, but would never truly meet definition of first class}}
{{omit from|Ada|Task could be completed, but would never truly meet definition of first class}}
{{omit from|Go|Retracting solution. Spirit of task not met.}}
{{omit from|Maxima}}
{{omit from|Maxima}}