"***********************************************************************************************"

Recursive Closures

This webpage, and those that follow, explores the utility of what will be called "m-M(x) closures"; i.e., closures resulting from statements "m = M(x)", where x can be any value, and "M" is basically defined as:

    const dF3x = () => {}

    function M (x) {
      return function go (func)
        {
            if (func === dF3x) return x;
            else x = func(x);
            return go;
        }
    }

It's sometimes useful to modify the basic definition of m-M(x) closures (above); for example, to make "m(dF3x) return a clone of x, rather than x. The modified definition of M used in the Rubik's cube example saves the names of functions operated on by m, making it convenient for players to reverse a series of moves by repeatedly pressing the "Q" key. Link to the reverse function

Concise and Transparent Function Composition

This anonymous, and therefore temporary, closure returns 10 after taking the square root of ((3 cubed times 4) minus 8): M(3)(v=>v**3)(v=>v*4)(v=>v-8)(Math.sqrt)(dF3x) // 10

Isolation of Sequences of Computations

The virtual Rubik's cube shown on the Rubik's cube page demonstrates key presses and button clicks turning the sides, middle sections, or entire body of the virtual Rubik's cube that is displayed in browsers. The application code contains two entwined representations of the cube; one written in JavaScript, and the other in HTML.

The Two Representations of the Virtual Cube

The JavaScript representation of the virtual Rubik's cube consists of 54 strings contained in an array of six nine-member arrays. This array of arrays is "x" in the application's m-M(x) closure. "m" handles events triggered by key presses and mouse clicks. Events that rearrange strings in the m-M(x) closure cause m to operate on one of the functions (let's call it "func") defined within the script tags. Pursuant to the definition of M, m(func) rearranges the strings of x, mutating x to func(x).

The HTML representation of the cube consists of 54 buttons contained in an array of three nine-member arrays, corresponding to the three sides of the cube which are visible in the browser: front, top, and right. Rotating the virtual cube does not change this fact. For example, clicking the top center square, clicking "Y", and pressing the "Y" key changes x in the m-M(x) closure and also in the DOM, since m(dF3x) is x pursuant to the definition of M.

                    <button
                        style="background-color: {m(dF3x)[4][4]}"
                        on:click={() => {
                            m = m(Yro);
                        }}
                    /> 

by x in an m-M(x) closure, where x is an aAny andrray of six nine-member arrays of the strings "blue", "green", "red", "orange", "yellow", and "white". These clicks and key presses call m on functions, causing those functions to operate on the Rubik's cube representation in the m-M(x) closure. Rearranging the color strings of x, which are reactive and embedded in the DOM as "background-color = m(dF3x)[j][k]" for j between 0 and 6, and k between 0 and 9, automatically transforms the background colors of the buttons that comprise the Rubik's cube representation in the DOM. Rearranging the buttons'background colors creates the appearance, in the browser, of the virtual Rubik's cube, or one of its sides or middle sections, rotating 45 degrees. For example, The top, center square seen in the browser corresponds to this button element in the DOM:

The function Yro rearranges the virtual Rubik's cube seen in the monitor in a manner corresponding to a 45-degree clockwise rotation of the entire Rubik's cube around the vertical axis. It operates on x inside of the m-M(x) closure, insulated from possible interactions with other JavaScript code. The only side effects are changes in the HTML buttons' background colors.

    <button
        style="background-color: {m(dF3x)[4][4]}"
        on:click={() => {
            m = m(Yro);
        }}
    />

The illustration below shows the color changes that are seen in browser monitors when the center square on the top of a solved virtual Rubik's cube is clicked three times. The color strings of the x array of arrays in the m-M(x) closure rearrange to Yro(x). Overall, three clicks change x to Yro(Yro(Yro(x))). The definition of Yro is in the appendix at the bottom of this page.

Screenshot3.png Screenshot3.png Screenshot3.png Screenshot3.png
Cloning With Astonishing Ease

Cloning is discussed on the Clone page. Deeply nested, self-referential, function-containing, complex and complicated objects are cloned with the greatest of ease.

Modifying M For Special Purposes

The definition of M can be modified to avoid mutation (push new results into an array, for example), reverse a series of actions as in theRubik's cube example, handle asynchronous functions, as in the cube reverse function, Async, and other purposes.

Efficiently Crunching Numbers

Martingale runs the Martingale betting strategy millions of times, demonstrating that even-odds games of chance are, in the long run, break-even endeavors. Sometimes you end up ahead, sometimes behind. The Martingale strategy doesn't change that.

to show that it neither increases nor decreases the odds of coming out ahead. x in the m(x)-M closure is [starting amount,1,goal,0] where "starting amount" is the amount of money the player tries to double. "goal is fixed, starting at "starting amount. m operates on the function "f1", which randomly generates 0 or 1 wth equal probability, increasing or decreasing v[1] (the mount of the bet) and v[0] (the players current stake).

If you go to Martingale, you can try it yourself, learn the betting algorithm, and see the outcomes of tens of thousands of coin flips. m needs only one function, f1, shown below.

    import { leftShift } from "mathjs";
    var log = console.log;
    var dF3x = () => {};

    function M(x) {
        return function go(func) {
            if (func === dF3x) return x;
            x = func(x);
            return go;
        };
    }
    var aa = 25;
    var m = M([aa,1,aa,0]); // x in the m(x)-M closure is [25,1,25,0]
 // The elements of x (above) represent a starting dollars, first bet, goal, and wins.

    function f1 (v) {
        let result = Math.floor(Math.random()*2);
        if (result) {           // 1 is true, 0 is false.
          v[0] += v[1];         // The player gains $1.00
          log("2<><><><><><><>, m(dF3x) is", m(dF3x));
          if (v[3] < aa) m(f1)  // Another coin flip, 
          else {
            log("Double", m(dF3x))
            return;
          }  
        }
        else {
            v[0] = v[0] - v[1];
            v[1] = leftShift(v[1], 1);          
            log("2******, m(dF3x) is", m(dF3x));
            if (v[1] > v[0]) {
              log("Fail", m(dF3x));
              return
            }
            else m(f1);
        } 
        return v;
      };
Back to the top
Appendix
The Virtual Rubik's Cube

Additional discussion is at Virtual Rubik's Cube

In the m-M(x) representation of a Rubik's cube as an array of six nine-member arrays of strings, the solved cube is x = ([ ["blue", "blue", "blue", "blue", "blue", "blue", "blue", "blue", "blue"], ["green", "green", "green", "green", "green", "green", "green", "green", "green"], ["red", "red", "red", "red", "red", "red", "red", "red", "red"], ["orange", "orange", "orange", "orange", "orange", "orange", "orange", "orange", "orange"], ["yellow", "yellow", "yellow", "yellow", "yellow", "yellow", "yellow", "yellow", "yellow"], ["white", "white", "white", "white", "white", "white", "white", "white", "white"] ] The default orientation of the visible sides of a solved cube is yellow on top, blue on the right, and orange facing outward.

When m(Yro) executes, Yro constructs an array of six nine-member arrays named "temp," using the 54 strings constituting x in its current state. Finally, pursuant to the definition of M, x = temp, the return value of Yro(x). Here's the definition of Yro:

    var Yro = function Yro(ar) {
        let temp = [];
        temp[0] = ar[2];
        temp[1] = ar[3];
        temp[2] = ar[1];
        temp[3] = ar[0];
        temp[4] = [
            ar[4][6],
            ar[4][3],
            ar[4][0],
            ar[4][7],
            ar[4][4],
            ar[4][1],
            ar[4][8],
            ar[4][5],
            ar[4][2],
        ];
        temp[5] = [
            ar[5][2],
            ar[5][5],
            ar[5][8],
            ar[5][1],
            ar[5][4],
            ar[5][7],
            ar[5][0],
            ar[5][3],
            ar[5][6],
        ];
        return temp;
    };

Further Discussion of the Fast and Efficient Virtual Rubik's Cube

Some of the code responsible for the virtual Rubik's cube is shown below. Here's the HTML code:

<div class="face front">
  <div class="grid">
    <button style="background-color: {m(dF3x)[3][0]}" on:click={() => {m = m(Fz)}}/>
    <button style="background-color: {m(dF3x)[3][1]}" on:click={() => {m = m(Cx)}}/>
    <button style="background-color: {m(dF3x)[3][2]}" on:click={() => {m = m(F)}}/>
    <button style="background-color: {m(dF3x)[3][3]}" on:click={() => {m = m(Cyr)}}/>
    <button style="background-color: {m(dF3x)[3][4]}" on:click={() => {m = m(Zro)}}/>
    <button style="background-color: {m(dF3x)[3][5]}" on:click={() => {m = m(Cy)}}/>
    <button style="background-color: {m(dF3x)[3][6]}" on:click={() => {m = m(Fz)}}/>
    <button style="background-color: {m(dF3x)[3][7]}" on:click={() => {m = m(Cxr)}}/>
    <button style="background-color: {m(dF3x)[3][8]}" on:click={() => {m = m(F)}}/>
  </div>
</div>

<div class="face right">
  <div class="grid">
    <button style="background-color: {m(dF3x)[0][0]}" on:click={() => {m = m(Rz)}}/>
    <button style="background-color: {m(dF3x)[0][1]}" on:click={() => {m = m(Cz)}}/>
    <button style="background-color: {m(dF3x)[0][2]}" on:click={() => {m = m(R)}}/>
    <button style="background-color: {m(dF3x)[0][3]}" on:click={() => {m = m(Cyr)}}/>
    <button style="background-color: {m(dF3x)[0][4]}" on:click={() => {m = m(Xro)}}/>
    <button style="background-color: {m(dF3x)[0][5]}" on:click={() => {m = m(Cy)}}/>
    <button style="background-color: {m(dF3x)[0][6]}" on:click={() => {m = m(Rz)}}/>
    <button style="background-color: {m(dF3x)[0][7]}" on:click={() => {m = m(Czr)}}/>
    <button style="background-color: {m(dF3x)[0][8]}" on:click={() => {m = m(R)}}/>
  </div>
</div>

<div class="face top">
  <div class="grid">
    <button style="background-color: {m(dF3x)[4][0]}" on:click={() => {m = m(Uz)}}/>
    <button style="background-color: {m(dF3x)[4][1]}" on:click={() => {m = m(Cx)}}/>
    <button style="background-color: {m(dF3x)[4][2]}" on:click={() => {m = m(U)}}/>
    <button style="background-color: {m(dF3x)[4][3]}" on:click={() => {m = m(Cz)}}/>
    <button style="background-color: {m(dF3x)[4][4]}" on:click={() => {m = m(Yro)}}/>
    <button style="background-color: {m(dF3x)[4][5]}" on:click={() => {m = m(Czr)}}/>
    <button style="background-color: {m(dF3x)[4][6]}" on:click={() => {m = m(Uz)}}/>
    <button style="background-color: {m(dF3x)[4][7]}" on:click={() => {m = m(Cxr)}}/>
    <button style="background-color: {m(dF3x)[4][8]}" on:click={() => {m = m(U)}}/>
  </div>        
</div>

A JavaScript representation of a solved virtual Rubik's cube is shown below. 'x' in the m-M(x) closure is an array of six nine-member arrays of strings. x[0] contains nine copies of "blue". The code that determines the colors of the initial right side of the virtual cube displayed in the broswer is shown in the middle block of HTML buttons above. Each of the nine lines specifies background-colors which are elements of x[0], all of which are "blue" when the m-M(x) closure is defined.

      var m = M([ ["blue", "blue", "blue", "blue", "blue", "blue", "blue", "blue", "blue"],
      ["green", "green", "green", "green", "green", "green", "green", "green", "green"],
      ["red", "red", "red", "red", "red", "red", "red", "red", "red"],
      ["orange", "orange", "orange", "orange", "orange", "orange", "orange", "orange", "orange"],
      ["yellow", "yellow", "yellow", "yellow", "yellow", "yellow", "yellow", "yellow", "yellow"],
      ["white", "white", "white", "white", "white", "white", "white", "white", "white"] ]);

After pressing "F", clicking the "F" button, or clicking the upper or lower right side of the front of the virtual cube, x in the m-M(x) closure rearranges to this configuration:

      var m = M([ ["yellow", "blue", "blue", "yellow", "blue", "blue", "yellow", "blue", "blue"],
      ["green", "green", "white", "green", "green", "white", "green", "green", "white"],
      ["red", "red", "red", "red", "red", "red", "red", "red", "red"],
      ["orange", "orange", "orange", "orange", "orange", "orange", "orange", "orange", "orange"],
      ["yellow", "yellow", "yellow", "yellow", "yellow", "yellow", "green", "green", "green"],
      ["blue", "blue", "blue", "white", "white", "white", "white", "white", "white"] ]);

And the cube looks like this:

Right side turned

Here's the definition of F:

function F(ar) {
    let temp = [];
    temp[0] = [
      ar[4][6],
      ar[0][1],
      ar[0][2],
      ar[4][7],
      ar[0][4],
      ar[0][5],
      ar[4][8],
      ar[0][7],
      ar[0][8],
    ];

    temp[1] = [
      ar[1][0],
      ar[1][1],
      ar[5][0],
      ar[1][3],
      ar[1][4],
      ar[5][1],
      ar[1][6],
      ar[1][7],
      ar[5][2],
    ];

    temp[2] = ar[2];

    temp[3] = [
      ar[3][6],
      ar[3][3],
      ar[3][0],
      ar[3][7],
      ar[3][4],
      ar[3][1],
      ar[3][8],
      ar[3][5],
      ar[3][2],
    ];

    temp[4] = [
      ar[4][0],
      ar[4][1],
      ar[4][2],
      ar[4][3],
      ar[4][4],
      ar[4][5],
      ar[1][8],
      ar[1][5],
      ar[1][2],
    ];

    temp[5] = [
      ar[0][6],
      ar[0][3],
      ar[0][0],
      ar[5][3],
      ar[5][4],
      ar[5][5],
      ar[5][6],
      ar[5][7],
      ar[5][8],
    ];
    return temp;
} 

F populates a temporary array "temp" with values taken from locations on the current configuration of x. It populates temp[0][0], temp[0][3], temp[0][6], with whatever strings happen to be at x[4][2], x[4][5], and x[4][8]. When m(F) returns temp, temp becomes the value of x in the m-M(x) closure.

Additional Protection of "x" in m-M(x) closures

If x is not a primitive value, changing m(dF3x) changes x in the m-M(x) closure. This can be convenient, as in the function "reverse" in Rubik's Cube. The array "ar" in the modified definition of M holds an array of the names of the functions called when users press keys or click buttons that change the virtual Rubik's cube. m(dF3ar) returns ar. "ob" is an object that produces the inverse of the Rubik's cube manipulation functions. For example, ob.R is Rz, the inverse of R. Here are the definitions of reverse and ob:

function reverse () { 
    m = m(ob[m(dF3ar).pop()]); // Pops a function name and runs its reverse.   
    m(dF3ar).pop(); // Discard the inverse functions's name, that m just 
                    // pushed onto ar (inside of the m-M(x) closure). 
  }
const ob = {'R': Rz, 'L': Lz, 'U': Uz, 'D': Dz, 'F': Fz, 'B': Bz, 'Cx': Cxr,
   'Cy': Cyr, 'Cz': Czr, 'Xro': Xror, 'Yro': Yror, 'Zro': Zror, 'Rz': R,
   'Lz': L, 'Uz': U, 'Dz': D, 'Fz': F, 'Bz': B, 'Cxr': Cx, 'Cyr': Cy, 'Czr': Cz,
   'Xror': Xro, 'Yror': Yro, 'Zror': Zro};

var log = console.log;
var dF3x = () => {};

function M(x) {
    return function go(func) {
        if (func === dF3x) return x;
        x = func(x);
        return go;
    };
}

var m = M({a:1, b:2});
var b = m(dF3x);  // b is just another name for x in the m-M(x) closure.
b.c = 3; 
log("b is", b);  // b is { a: 1, b: 2, c: 3 }
log("m(dF3x) is", m(dF3x));  // m(dF3x) is { a: 1, b: 2, c: 3 }
// Mutating b mutated x in the m-M(x) closure.

function M(x) {
    return function go(func) {
        if (func === dF3x) return JSON.parse(JSON.stringify(x));
        x = func(x);
        return go;
    };
}

var m = M({a:1, b:2});
var b = m(dF3x);  // b is a clone
b.c = 3;
log("b is", b);  // b is { a: 1, b: 2, c: 3 }
log("m(dF3x) is", m(dF3x));  // m(dF3x) is { a: 1, b: 2 }
// x in the m-M(x) closure is not affected by the modification of b.

JSON.parse(JSON.stringify(x)) is unable to make clones of functions, 
undefined values, Symbols, circular references, custom class instances (methods and prototype), dates (converted to strings), regular Expressions (lost), typed Arrays and special objects (converted to plain objects).

JSON.parse(JSON.stringify(x)) is a common technique to create a deep clone of an object in JavaScript. However, it fails to handle certain types of data. Here are the values of x for which this method cannot make a proper clone:

(1) Functions: Functions are not valid JSON data types, so they are omitted during stringification.

const obj = { fn: function() { return "hello"; } };
JSON.parse(JSON.stringify(obj)); // { } - the function is lost

(2) Undefined values: undefined is not a valid JSON type, so any property with undefined as a value will be omitted.

const obj = { key: undefined };
JSON.parse(JSON.stringify(obj)); // { } - the undefined property is lost

(3) Symbol values: Symbols are not valid in JSON and are excluded during stringification.

const obj = { key: Symbol("sym") };
JSON.parse(JSON.stringify(obj)); // { } - the symbol is lost

(4) Circular references: JSON cannot represent circular structures, so attempting to stringify an object with circular references will throw an error.

const obj = {};
obj.self = obj;
JSON.stringify(obj); // Error: Converting circular structure to JSON

(5) Custom class instances: Instances of custom classes will be converted to plain objects, and their methods and prototype chain will be lost.

class MyClass {
  constructor() { this.val = 10; }
  method() { return this.val; }
}
const obj = new MyClass();
JSON.parse(JSON.stringify(obj)); // { val: 10 } - methods are lost

(6) Date objects: Dates will be serialized as strings and will not retain their Date type.

const obj = { date: new Date() };
JSON.parse(JSON.stringify(obj)); // { date: "2024-09-10T00:00:00.000Z" } - Date is converted to string

(7) Regular Expressions: RegExps are not supported and will be converted to empty objects.

const obj = { regex: /abc/ };
JSON.parse(JSON.stringify(obj)); // { regex: {} } - Regular expression is lost

(8) Typed Arrays and other special objects: Objects like Map, Set, WeakMap, WeakSet, Int8Array, Uint8Array, etc., will lose their special behavior and be serialized as empty or plain objects.

const obj = { map: new Map(), set: new Set() };
JSON.parse(JSON.stringify(obj)); // { map: {}, set: {} } - Map and Set are lost

While not universally effective, this method covers many cases:

You can combine Object.create(Object.getPrototypeOf(obj)) 
with Object.getOwnPropertyDescriptors(obj) to both preserve the prototype and 
copy the own properties of obj using property descriptors. This approach 
allows you to create a new object with the same prototype as obj, while also 
copying all its own properties (including non-enumerable properties and 
getters/setters) in a concise and efficient way.

How It Works:

    Object.getOwnPropertyDescriptors(obj) returns an object containing 
    all the property descriptors of obj's own properties. Object.create() 
    allows you to specify the prototype for the new object and also pass 
    a property descriptor object as the second argument to define its properties.

Here’s how you can use them together:

javascript

const newObj = Object.create(
  Object.getPrototypeOf(obj),   // Set the prototype of the new object
  Object.getOwnPropertyDescriptors(obj)  // Copy all own properties of 'obj'
);

Example:

javascript

const obj = {
  a: 1,
  get b() { return this.a + 1; }
};

// Create a new object with the same prototype and properties as 'obj'
const newObj = Object.create(
  Object.getPrototypeOf(obj), 
  Object.getOwnPropertyDescriptors(obj)
);

console.log(newObj.a);  // Output: 1
console.log(newObj.b);  // Output: 2 (getter works)
console.log(Object.getPrototypeOf(newObj) === Object.getPrototypeOf(obj)); // true

Why This Is Useful:

    Retains Prototype: You retain the original prototype chain of obj, 
    meaning newObj will inherit methods and properties from the same 
    prototype as obj. Copies Own Properties: The own properties 
    (including getters, setters, and non-enumerable properties) of obj 
    are copied to newObj. Efficient: This is an efficient way to create 
    a new object with the same prototype and properties, without 
    manually copying or assigning them.

    However, deep copying is still not automatic: If any of the properties are objects 
    themselves, they will be shallow copied, and you may need to handle deep 
    copying manually if necessary. Works for non-enumerable properties: This 
    method also copies non-enumerable properties, which Object.assign() would 
    not handle.

Example With Non-enumerable Properties:

const obj = {};

Object.defineProperty(obj, 'a', {
  value: 42,
  enumerable: true,
  writable: true,
  configurable: true
});

Object.defineProperty(obj, 'b', {
  value: 100,
  enumerable: false,  // Non-enumerable property
  writable: true,
  configurable: true
});

const newObj = Object.create(
  Object.getPrototypeOf(obj),
  Object.getOwnPropertyDescriptors(obj)
);

console.log(newObj.a);   // Output: 42
console.log(newObj.b);   // Output: 100 (non-enumerable property is copied)
console.log(Object.keys(newObj)); // Output: ['a'], 'b' is non-enumerable