First class environments

From Rosetta Code
Revision as of 06:13, 3 April 2012 by rosettacode>Gerard Schildberger (→‎{{header|REXX}}: added the REXX language. -- ~~~~)
Task
First class environments
You are encouraged to solve this task according to the task description, using any language you may know.

According to Wikipedia, "In computing, a first-class object ... is an entity that can be constructed at run-time, passed as a parameter, returned from a subroutine, or assigned into a variable".

Often this term is used in the context of "first class functions". In an analogous way, a programming language may support "first class environments".

The environment is minimally, the set of variables accessable to a statement being executed. Change the environments and the same statement could produce different results when executed.

Often an environment is captured in a closure, which encapsulates a function together with an environment. That environment, however, is not first-class, as it cannot be created, passed etc. independently from the function's code.

Therefore, a first class environment is a set of variable bindings which can be constructed at run-time, passed as a parameter, returned from a subroutine, or assigned into a variable. It is like a closure without code. A statement must be able to be executed within a stored first class environment and act according to the environment variable values stored within.

The task: Build a dozen environments, and a single piece of code to be run repeatedly in each of these envionments.

Each environment contains the bindings for two variables: A value in the Hailstone sequence, and a count which is incremented until the value drops to 1. The initial hailstone values are 1 through 12, and the count in each environment is zero.

When the code runs, it calculates the next hailstone step in the current environment (unless the value is already 1) and counts the steps. Then it prints the current value in a tabular form.

When all hailstone values dropped to 1, processing stops, and the total number of hailstone steps for each environment is printed.

C

Well, this fits the semantics, not sure about the spirit… <lang C>#include <stdio.h>

  1. define JOBS 12
  2. define jobs(a) for (switch_to(a = 0); a < JOBS || !printf("\n"); switch_to(++a))

typedef struct { int seq, cnt; } env_t;

env_t env[JOBS] = Template:0, 0; int *seq, *cnt;

void hail() { printf("% 4d", *seq); if (*seq == 1) return; ++*cnt; *seq = (*seq & 1) ? 3 * *seq + 1 : *seq / 2; }

void switch_to(int id) { seq = &env[id].seq; cnt = &env[id].cnt; }

int main() { int i; jobs(i) { env[i].seq = i + 1; }

again: jobs(i) { hail(); } jobs(i) { if (1 != *seq) goto again; }

printf("COUNTS:\n"); jobs(i) { printf("% 4d", *cnt); }

return 0; }</lang>

Output:
   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

Go

This example is incorrect. Please fix the code and remove this message.

Details: 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>

Output:
   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

Icon and Unicon

The simplest way to create an environment with variables isolated from code in Icon/Unicon is to create instances of records or class objects. <lang Icon>link printf

procedure main()

  every put(environment := [], hailenv(1 to 12,0))  # setup environments 
  printf("Sequences:\n")
  while (e := !environment).sequence > 1 do {
     every hailstep(!environment) 
     printf("\n")
     }
  printf("\nCounts:\n")
  every printf("%4d ",(!environment).count)
  printf("\n")

end

record hailenv(sequence,count)

procedure hailstep(env)

  printf("%4d ",env.sequence)
   if env.sequence ~= 1 then {
       env.count +:= 1
       if env.sequence % 2 = 0 then env.sequence /:= 2 
       else env.sequence := 3 * env.sequence + 1
       }

end</lang>

printf.icn provides formatting

Output:
Sequences:
   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 

J

I have tried to determine what makes this task interesting (see talk page), but I am still confused.

Here is my current interpretation of the task requirements: <lang j>coclass 'hailstone'

step=:3 :0

 NB. and determine next element in hailstone sequence
 if.1=N do. N return.end.
   NB. count how many times this has run when N was not 1
   STEP=:STEP+1
 if.0=2|N do.
   N=: N%2
 else.
   N=: 1 + 3*N
 end.

)

create=:3 :0

 STEP=: 0
 N=: y

)

current=:3 :0

 N__y

)

run1=:3 :0

 step__y
 STEP__y

)

run=:3 :0

 old=: 
 while. -. old -: state=: run1"0 y do.
   smoutput 4j0 ": current"0 y
   old=: state
 end.

)</lang>

Example use:

<lang j> environments=: conew&'hailstone'"0 (1+i.12)

  run_hailstone_ environments
  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
  1   1   1   1   1   1   1   1   1   1   1   1

0 1 7 2 5 8 16 3 19 6 14 9</lang> In essence: run is a static method of the class hailstone which, given a list of objects of the class runs all of them until their hailstone sequence number stops changing. It also displays the hailstone sequence number from each of the objects at each step. Its result is the step count from each object.

PicoLisp

Runtime environments can be controlled with the 'job' function: <lang PicoLisp>(let Envs

  (mapcar
     '((N) (list (cons 'N N) (cons 'Cnt 0)))  # Build environments
     (range 1 12) )
  (while (find '((E) (job E (> N 1))) Envs)   # Until all values are 1:
     (for E Envs
        (job E                                # Use environment 'E'
           (prin (align 4 N))
           (unless (= 1 N)
              (inc 'Cnt)                      # Increment step count
              (setq N
                 (if (bit? 1 N)               # Calculate next hailstone value
                    (inc (* N 3))
                    (/ N 2) ) ) ) ) )
     (prinl) )
  (prinl (need 48 '=))
  (for E Envs                                 # For each environment 'E'
     (job E
        (prin (align 4 Cnt)) ) )              # print the step count
  (prinl) )</lang>
Output:
   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
================================================
   0   1   7   2   5   8  16   3  19   6  14   9

Python

In Python, name bindings are held in dicts, one for global scope and another for local scope. When exec'ing code, you are allowed to give your own dictionaries for these scopes. In this example, two names are held in dictionaries that are used as the local scope for the evaluation of source. <lang python>environments = [{'cnt':0, 'seq':i+1} for i in range(12)]

code = print('% 4d' % seq, end=) if seq != 1:

   cnt += 1
   seq = 3 * seq + 1 if seq & 1 else seq // 2

while any(env['seq'] > 1 for env in environments):

   for env in environments:
       exec(code, globals(), env)
   print()

print('Counts') for env in environments:

   print('% 4d' % env['cnt'], end=)

print()</lang>

Output:
   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

REXX

<lang rexx> /*REXX program illustrates first-class environments (using hailstone #s)*/

parse arg #envs .; env_.=; if #envs== then #envs=12

/*─────────────────────────────────────initialize (twelve) environments.*/

 do init=1 for #envs;  env_.init=init;  end

/*─────────────────────────────────────process environments until done. */

    do forever until env_.0; env_.0=1
         do k=1 for #envs
         env_.k=env_.k hailstone(k)   /*where the rubber meets the road*/
         end   /*k*/
    end        /*forever*/

/*─────────────────────────────────────show results in tabular form. */ count=0

 do lines=-1 until _==; _=
         do j=1 for #envs
               select
               when count== 1 then _=_ right(words(env_.j)-1,3)
               when lines==-1 then _=_ right(j,3)
               when lines== 0 then _=_ right(,3,'-')
               otherwise       _=_ right(word(env_.j,lines),3)
               end   /*select*/
         end       /*j*/
 if count==1 then count=2
 _=strip(_,'T')
 if _== then count=count+1
 if count==1 then _=copies(' ===',#envs)
 if _\== then say substr(_,2)
 end              /*lines*/

exit

/*─────────────────────────────────────HAILSTONE (Collatz) subroutine───*/ hailstone: procedure expose env_.; arg n;_=word(env_.n,words(env_.n)) if _==1 then return ; env_.0=0; if _//2==0 then return _%2; return _*3+1 </lang> Output when using the default input ( 12 ):

  1   2   3   4   5   6   7   8   9  10  11  12
--- --- --- --- --- --- --- --- --- --- --- ---
  1   2   3   4   5   6   7   8   9  10  11  12
      1  10   2  16   3  22   4  28   5  34   6
          5   1   8  10  11   2  14  16  17   3
         16       4   5  34   1   7   8  52  10
          8       2  16  17      22   4  26   5
          4       1   8  52      11   2  13  16
          2           4  26      34   1  40   8
          1           2  13      17      20   4
                      1  40      52      10   2
                         20      26       5   1
                         10      13      16
                          5      40       8
                         16      20       4
                          8      10       2
                          4       5       1
                          2      16
                          1       8
                                  4
                                  2
                                  1
=== === === === === === === === === === === ===
  0   1   7   2   5   8  16   3  19   6  14   9

Output when the input is 50 :

  1   2   3   4   5   6   7   8   9  10  11  12  13  14  15  16  17  18  19  20  21  22  23  24  25  26  27  28  29  30  31  32  33  34  35  36  37  38  39  40  41  42  43  44  45  46  47  48  49  50
--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
  1   2   3   4   5   6   7   8   9  10  11  12  13  14  15  16  17  18  19  20  21  22  23  24  25  26  27  28  29  30  31  32  33  34  35  36  37  38  39  40  41  42  43  44  45  46  47  48  49  50
      1  10   2  16   3  22   4  28   5  34   6  40   7  46   8  52   9  58  10  64  11  70  12  76  13  82  14  88  15  94  16 100  17 106  18 112  19 118  20 124  21 130  22 136  23 142  24 148  25
          5   1   8  10  11   2  14  16  17   3  20  22  23   4  26  28  29   5  32  34  35   6  38  40  41   7  44  46  47   8  50  52  53   9  56  58  59  10  62  64  65  11  68  70  71  12  74  76
         16       4   5  34   1   7   8  52  10  10  11  70   2  13  14  88  16  16  17 106   3  19  20 124  22  22  23 142   4  25  26 160  28  28  29 178   5  31  32 196  34  34  35 214   6  37  38
          8       2  16  17      22   4  26   5   5  34  35   1  40   7  44   8   8  52  53  10  58  10  62  11  11  70  71   2  76  13  80  14  14  88  89  16  94  16  98  17  17 106 107   3 112  19
          4       1   8  52      11   2  13  16  16  17 106      20  22  22   4   4  26 160   5  29   5  31  34  34  35 214   1  38  40  40   7   7  44 268   8  47   8  49  52  52  53 322  10  56  58
          2           4  26      34   1  40   8   8  52  53      10  11  11   2   2  13  80  16  88  16  94  17  17 106 107      19  20  20  22  22  22 134   4 142   4 148  26  26 160 161   5  28  29
          1           2  13      17      20   4   4  26 160       5  34  34   1   1  40  40   8  44   8  47  52  52  53 322      58  10  10  11  11  11  67   2  71   2  74  13  13  80 484  16  14  88
                      1  40      52      10   2   2  13  80      16  17  17          20  20   4  22   4 142  26  26 160 161      29   5   5  34  34  34 202   1 214   1  37  40  40  40 242   8   7  44
                         20      26       5   1   1  40  40       8  52  52          10  10   2  11   2  71  13  13  80 484      88  16  16  17  17  17 101     107     112  20  20  20 121   4  22  22
                         10      13      16          20  20       4  26  26           5   5   1  34   1 214  40  40  40 242      44   8   8  52  52  52 304     322      56  10  10  10 364   2  11  11
                          5      40       8          10  10       2  13  13          16  16      17     107  20  20  20 121      22   4   4  26  26  26 152     161      28   5   5   5 182   1  34  34
                         16      20       4           5   5       1  40  40           8   8      52     322  10  10  10 364      11   2   2  13  13  13  76     484      14  16  16  16  91      17  17
                          8      10       2          16  16          20  20           4   4      26     161   5   5   5 182      34   1   1  40  40  40  38     242       7   8   8   8 274      52  52
                          4       5       1           8   8          10  10           2   2      13     484  16  16  16  91      17          20  20  20  19     121      22   4   4   4 137      26  26
                          2      16                   4   4           5   5           1   1      40     242   8   8   8 274      52          10  10  10  58     364      11   2   2   2 412      13  13
                          1       8                   2   2          16  16                      20     121   4   4   4 137      26           5   5   5  29     182      34   1   1   1 206      40  40
                                  4                   1   1           8   8                      10     364   2   2   2 412      13          16  16  16  88      91      17             103      20  20
                                  2                                   4   4                       5     182   1   1   1 206      40           8   8   8  44     274      52             310      10  10
                                  1                                   2   2                      16      91             103      20           4   4   4  22     137      26             155       5   5
                                                                      1   1                       8     274             310      10           2   2   2  11     412      13             466      16  16
                                                                                                  4     137             155       5           1   1   1  34     206      40             233       8   8
                                                                                                  2     412             466      16                      17     103      20             700       4   4
                                                                                                  1     206             233       8                      52     310      10             350       2   2
                                                                                                        103             700       4                      26     155       5             175       1   1
                                                                                                        310             350       2                      13     466      16             526
                                                                                                        155             175       1                      40     233       8             263
                                                                                                        466             526                              20     700       4             790
                                                                                                        233             263                              10     350       2             395
                                                                                                        700             790                               5     175       1             186
                                                                                                        350             395                              16     526                     593
                                                                                                        175             186                               8     263                     780
                                                                                                        526             593                               4     790                     890
                                                                                                        263             780                               2     395                     445
                                                                                                        790             890                               1     186                     336
                                                                                                        395             445                                     593                     668
                                                                                                        186             336                                     780                     334
                                                                                                        593             668                                     890                     167
                                                                                                        780             334                                     445                     502
                                                                                                        890             167                                     336                     251
                                                                                                        445             502                                     668                     754
                                                                                                        336             251                                     334                     377
                                                                                                        668             754                                     167                     132
                                                                                                        334             377                                     502                     566
                                                                                                        167             132                                     251                     283
                                                                                                        502             566                                     754                     850
                                                                                                        251             283                                     377                     425
                                                                                                        754             850                                     132                     276
                                                                                                        377             425                                     566                     638
                                                                                                        132             276                                     283                     319
                                                                                                        566             638                                     850                     958
                                                                                                        283             319                                     425                     479
                                                                                                        850             958                                     276                     438
                                                                                                        425             479                                     638                     719
                                                                                                        276             438                                     319                     158
                                                                                                        638             719                                     958                     079
                                                                                                        319             158                                     479                     238
                                                                                                        958             079                                     438                     619
                                                                                                        479             238                                     719                     858
                                                                                                        438             619                                     158                     429
                                                                                                        719             858                                     079                     288
                                                                                                        158             429                                     238                     644
                                                                                                        079             288                                     619                     822
                                                                                                        238             644                                     858                     911
                                                                                                        619             822                                     429                     734
                                                                                                        858             911                                     288                     367
                                                                                                        429             734                                     644                     102
                                                                                                        288             367                                     822                     051
                                                                                                        644             102                                     911                     154
                                                                                                        822             051                                     734                     077
                                                                                                        911             154                                     367                     232
                                                                                                        734             077                                     102                     616
                                                                                                        367             232                                     051                     308
                                                                                                        102             616                                     154                     154
                                                                                                        051             308                                     077                     577
                                                                                                        154             154                                     232                     732
                                                                                                        077             577                                     616                     866
                                                                                                        232             732                                     308                     433
                                                                                                        616             866                                     154                     300
                                                                                                        308             433                                     577                     650
                                                                                                        154             300                                     732                     325
                                                                                                        577             650                                     866                     976
                                                                                                        732             325                                     433                     488
                                                                                                        866             976                                     300                     244
                                                                                                        433             488                                     650                     122
                                                                                                        300             244                                     325                      61
                                                                                                        650             122                                     976                     184
                                                                                                        325              61                                     488                      92
                                                                                                        976             184                                     244                      46
                                                                                                        488              92                                     122                      23
                                                                                                        244              46                                      61                      70
                                                                                                        122              23                                     184                      35
                                                                                                         61              70                                      92                     106
                                                                                                        184              35                                      46                      53
                                                                                                         92             106                                      23                     160
                                                                                                         46              53                                      70                      80
                                                                                                         23             160                                      35                      40
                                                                                                         70              80                                     106                      20
                                                                                                         35              40                                      53                      10
                                                                                                        106              20                                     160                       5
                                                                                                         53              10                                      80                      16
                                                                                                        160               5                                      40                       8
                                                                                                         80              16                                      20                       4
                                                                                                         40               8                                      10                       2
                                                                                                         20               4                                       5                       1
                                                                                                         10               2                                      16
                                                                                                          5               1                                       8
                                                                                                         16                                                       4
                                                                                                          8                                                       2
                                                                                                          4                                                       1
                                                                                                          2
                                                                                                          1
=== === === === === === === === === === === === === === === === === === === === === === === === === === === === === === === === === === === === === === === === === === === === === === === === === ===
  0   1   7   2   5   8  16   3  19   6  14   9   9  17  17   4  12  20  20   7   7  15  15  10  23  10 111  18  18  18 106   5  26  13  13  21  21  21  34   8 109   8  29  16  16  16 104  11  24  24

Ruby

Translation of: PicoLisp

The object is an environment for instance variables. These variables use the @ sigil. We create 12 objects, and put @n and @cnt inside these objects. We use Object#instance_eval to switch the current object and bring those instance variables into scope. <lang ruby># Build environments envs = (1..12).map do |n|

 Object.new.instance_eval {@n = n; @cnt = 0; self}

end

  1. Until all values are 1:

while envs.find {|e| e.instance_eval {@n} > 1}

 envs.each do |e|
   e.instance_eval do          # Use environment _e_
     printf "%4s", @n
     unless 1 == @n
       @cnt += 1               # Increment step count
       @n = if 1 & @n == 1     # Calculate next hailstone value
              @n * 3 + 1
            else
              @n / 2
            end
     end
   end
 end
 puts

end puts '=' * 48 envs.each do |e| # For each environment _e_

 e.instance_eval do
   printf "%4s", @cnt          # print the step count
 end

end puts</lang> Ruby also provides the binding, an environment for local variables. The problem is that local variables have lexical scope. Ruby needs the lexical scope to parse Ruby code. So, the only way to use a binding is to evaluate a string of Ruby code. We use Kernel#binding to create the bindings, and Kernel#eval to evaluate strings in these bindings. The lines between <<-'eos' and eos are multi-line string literals. <lang ruby># Build environments envs = (1..12).map do |n|

 e = class Object
       # This is a new lexical scope with no local variables.
       # Create a new binding here.
       binding
     end
 eval(<<-'eos', e).call(n)
   n, cnt = nil, 0
   proc {|arg| n = arg}
 eos
 next e

end

  1. Until all values are 1:

while envs.find {|e| eval('n > 1', e)}

 envs.each do |e|
   eval(<<-'eos', e)           # Use environment _e_
     printf "%4s", n
     unless 1 == n
       cnt += 1                # Increment step count
       n = if 1 & n == 1       # Calculate next hailstone value
             n * 3 + 1
           else
             n / 2
           end
     end
   eos
 end
 puts

end puts '=' * 48 envs.each do |e| # For each environment _e_

 eval(<<-'eos', e)
   printf "%4s", cnt           # print the step count
 eos

end puts</lang>

Tcl

The simplest way to make a first-class environment in Tcl is to use a dictionary; the dict with command (and dict update; not shown here) will expand a dictionary and bind it to variables for the duration of its body script. <lang tcl>package require Tcl 8.5

for {set i 1} {$i <= 12} {incr i} {

   dict set hailenv hail$i [dict create num $i steps 0]

} while 1 {

   set loopagain false
   foreach k [dict keys $hailenv] {

dict with hailenv $k { puts -nonewline [format %4d $num] if {$num == 1} { continue } elseif {$num & 1} { set num [expr {3*$num + 1}] } else { set num [expr {$num / 2}] } set loopagain true incr steps }

   }
   puts ""
   if {!$loopagain} break

} puts "Counts..." foreach k [dict keys $hailenv] {

   dict with hailenv $k {

puts -nonewline [format %4d $steps]

   }

} puts ""</lang>

Output:
   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
   1   1   1   1   1   1   1   1   1   1   1   1
Counts...
   0   1   7   2   5   8  16   3  19   6  14   9