How to resolve the algorithm Amb step by step in the JavaScript programming language

Published on 12 May 2024 09:40 PM

How to resolve the algorithm Amb step by step in the JavaScript programming language

Table of Contents

Problem Statement

Define and give an example of the Amb operator. The Amb operator (short for "ambiguous") expresses nondeterminism. This doesn't refer to randomness (as in "nondeterministic universe") but is closely related to the term as it is used in automata theory ("non-deterministic finite automaton"). The Amb operator takes a variable number of expressions (or values if that's simpler in the language) and yields a correct one which will satisfy a constraint in some future computation, thereby avoiding failure. Problems whose solution the Amb operator naturally expresses can be approached with other tools, such as explicit nested iterations over data sets, or with pattern matching. By contrast, the Amb operator appears integrated into the language. Invocations of Amb are not wrapped in any visible loops or other search patterns; they appear to be independent. Essentially Amb(x, y, z) splits the computation into three possible futures: a future in which the value x is yielded, a future in which the value y is yielded and a future in which the value z is yielded. The future which leads to a successful subsequent computation is chosen. The other "parallel universes" somehow go away. Amb called with no arguments fails. For simplicity, one of the domain values usable with Amb may denote failure, if that is convenient. For instance, it is convenient if a Boolean false denotes failure, so that Amb(false) fails, and thus constraints can be expressed using Boolean expressions like Amb(x * y == 8) which unless x and y add to four. A pseudo-code program which satisfies this constraint might look like: The output is 2 4 because Amb(1, 2, 3) correctly chooses the future in which x has value 2, Amb(7, 6, 4, 5) chooses 4 and consequently Amb(x * y = 8) produces a success. Alternatively, failure could be represented using strictly Amb(): Or else Amb could take the form of two operators or functions: one for producing values and one for enforcing constraints: where Ambassert behaves like Amb() if the Boolean expression is false, otherwise it allows the future computation to take place, without yielding any value. The task is to somehow implement Amb, and demonstrate it with a program which chooses one word from each of the following four sets of character strings to generate a four-word sentence: The constraint to be satisfied is that the last character of each word (other than the last) is the same as the first character of its successor. The only successful sentence is "that thing grows slowly"; other combinations do not satisfy the constraint and thus fail. The goal of this task isn't to simply process the four lists of words with explicit, deterministic program flow such as nested iteration, to trivially demonstrate the correct output. The goal is to implement the Amb operator, or a facsimile thereof that is possible within the language limitations.

Let's start with the solution:

Step by Step solution about How to resolve the algorithm Amb step by step in the JavaScript programming language

Source Code Explanation

ambRun Function:

  • Purpose: Implements amb combinator.
  • Input: Function to be executed with amb function and fail function.
  • Output: Returns a value or undefined if all possibilities have been exhausted.
  • How it works:
    • Initializes an empty array of choices.
    • Wraps the input function in a try-catch block to handle backtracking.
    • Tries to execute the function, tracking the index of the current choice.
    • If an exception is thrown (indicating a dead end), it backtracks by popping the last choice from the array and incrementing its index.
    • If all choices have been exhausted, it returns undefined.
    • If a valid value is returned, it exits the loop.

Amb Function:

  • Purpose: Implements the amb combinator for the monadic choice.
  • Input: Array of values.
  • Output: Returns one of the values from the array.
  • How it works:
    • If the array is empty, it throws an exception to indicate a dead end.
    • If the index is equal to the length of the choices array, it adds a new choice object to the array.
    • It then returns the value at the current index.

Example Usage:

The example usage demonstrates how to generate a sentence by making choices from different lists of words.

  • ambRun Function:
    • Passes a lambda function to ambRun that takes two arguments: the amb function (for making choices) and a fail function.
  • Linked Function:
    • Checks if two words are linked, e.g., "elephant" and "thing" are linked because "t" is the last character of "elephant" and the first character of "thing".
  • amb Function:
    • Selects random words from the given lists and verifies that they are linked.
  • Final Result:
    • Returns the generated sentence, e.g., "that thing grows slowly".

Alternative Implementation Using Monadic Choice:

The second part of the code provides an alternative implementation of the amb combinator using monadic choice.

  • amb Function:
    • Takes an array of values and a function that takes one value and returns an array of output values.
    • Returns an array containing the results of applying the function to each value in the input array.
  • when Function:
    • Takes a predicate and an array.
    • Returns the input array if the predicate is true, otherwise returns an empty array.
  • Example Usage:
    • Uses the amb and when functions to generate a sentence, similar to the previous example.

Overall:

This code demonstrates the use of the amb combinator in JavaScript, allowing for non-deterministic or backtracking-based computations. It provides two implementations of the amb combinator: one using a manual backtracking approach and the other using monadic choice.

Source code in the javascript programming language

function ambRun(func) {
    var choices = [];
    var index;

    function amb(values) {
        if (values.length == 0) {
            fail();
        }
        if (index == choices.length) {
            choices.push({i: 0,
                          count: values.length});
        }
        var choice = choices[index++];
        return values[choice.i];
    }

    function fail() { throw fail; }

    while (true) {
        try {
            index = 0;
            return func(amb, fail);
        } catch (e) {
            if (e != fail) {
                throw e;
            }
            var choice;
            while ((choice = choices.pop()) && ++choice.i == choice.count) {}
            if (choice == undefined) {
                return undefined;
            }
            choices.push(choice);
        }
    }
}

ambRun(function(amb, fail) {
    function linked(s1, s2) {
        return s1.slice(-1) == s2.slice(0, 1);
    }

    var w1 = amb(["the", "that", "a"]);
    var w2 = amb(["frog", "elephant", "thing"]);
    if (!linked(w1, w2)) fail();

    var w3 = amb(["walked", "treaded", "grows"]);
    if (!linked(w2, w3)) fail();

    var w4 = amb(["slowly", "quickly"]);
    if (!linked(w3, w4)) fail();

    return [w1, w2, w3, w4].join(' ');
});  // "that thing grows slowly"


(() => {
    'use strict';

    // amb :: [a] -> (a -> [b]) -> [b]
    const amb = xs => f =>
        xs.reduce((a, x) => a.concat(f(x)), []);

    // when :: Bool -> [a] -> [a]
    const when = p =>
        xs => p ? (
            xs
        ) : [];


    // TEST -----------------------------------------------
    const main = () => {

        // joins :: String -> String -> Bool
        const joins = (a, b) =>
            b[0] === last(a);

        console.log(
            amb(['the', 'that', 'a'])
            (w1 => when(true)(

                amb(['frog', 'elephant', 'thing'])
                (w2 => when(joins(w1, w2))(

                    amb(['walked', 'treaded', 'grows'])
                    (w3 => when(joins(w2, w3))(

                        amb(['slowly', 'quickly'])
                        (w4 => when(joins(w3, w4))(

                            unwords([w1, w2, w3, w4])

                        ))
                    ))
                ))
            ))
        );
    };

    // GENERIC FUNCTIONS ----------------------------------  

    // last :: [a] -> a
    const last = xs =>
        0 < xs.length ? xs.slice(-1)[0] : undefined;

    // unwords :: [String] -> String
    const unwords = xs => xs.join(' ');

    // MAIN ---
    return main();
})();


  

You may also check:How to resolve the algorithm Apply a digital filter (direct form II transposed) step by step in the Phixmonti programming language
You may also check:How to resolve the algorithm Bitmap/Bresenham's line algorithm step by step in the Assembly programming language
You may also check:How to resolve the algorithm Keyboard input/Flush the keyboard buffer step by step in the Vedit macro language programming language
You may also check:How to resolve the algorithm Leap year step by step in the Logtalk programming language
You may also check:How to resolve the algorithm Infinity step by step in the OpenEdge/Progress programming language