All Downloads are FREE. Search and download functionalities are using the official Maven repository.

cl.ravenhill.keen.prog.Program.kt Maven / Gradle / Ivy

There is a newer version: 1.1.1
Show newest version
package cl.ravenhill.keen.prog

import cl.ravenhill.jakt.Jakt.constraints
import cl.ravenhill.jakt.constraints.collections.HaveSize
import cl.ravenhill.keen.ExperimentalKeen
import cl.ravenhill.keen.utils.trees.Tree
import java.util.Objects


/**
 * Represents a program structure in the form of a tree where each node is a reducible expression. The `Program` class
 * extends the [Tree] interface, enabling it to function as a node within a larger program tree. This class is part of
 * the experimental features in the Keen library and is tailored for encapsulating computational logic in a tree-like
 * structure.
 *
 * ## Constraints:
 * - The arity of the reducible expression ([Reducible.arity]) must equal the number of children. This ensures the
 *   structural integrity and correctness of the program tree.
 *
 * ## Usage:
 * The `Program` class is instrumental in representing and manipulating structured programs in computational models,
 * such as genetic programming or complex expression trees. It facilitates the creation of hierarchical, tree-based
 * computational structures.
 *
 * ### Example:
 * ```
 * @OptIn(ExperimentalKeen::class)
 * val program = Program(reducibleExpression, listOf(childProgram1, childProgram2))
 * val result = program(environment, arg1, arg2)
 * // result holds the evaluation outcome of the program
 * ```
 *
 * @param V The type of values processed by the reducible expressions in the program.
 * @param value The reducible expression at this node of the program.
 * @param children The child nodes of this program, each a `Program` instance.
 * @property arity The arity (number of arguments) of the reducible expression.
 * @property nodes A depth-first list of all program nodes in the tree, starting from the current node.
 * @property root An alias for the first node in the [nodes] list.
 * @constructor Creates a new `Program` instance, ensuring that the number of children matches the arity of the
 *   provided reducible expression.
 */
@ExperimentalKeen
class Program(
    override val value: Reducible,
    override val children: List> = emptyList()
) : Tree, Program> {

    init {
        constraints {
            "The arity of the reducible expression must be equal to the number of children" {
                children must HaveSize(value.arity)
            }
        }
    }

    override val arity: Int = value.arity

    override val nodes: List> by lazy { listOf(this) + children.flatMap { it.nodes } }

    val root: Program = nodes.first()

    /**
     * Creates and returns a new instance of the `Program` class with a specified reducible expression and list of
     * children.
     *
     * This method overrides the `createNode` method from the `Tree` interface, providing a way to construct new
     * `Program` nodes with given values and children. It utilizes the [copy] function to facilitate the creation of
     * the new node.
     *
     * ## Functionality:
     * - Constructs a new `Program` instance that encapsulates the provided reducible expression (`value`) and the
     *   specified list of children (`children`).
     *
     * ## Usage:
     * The `createNode` method is particularly useful in scenarios involving tree manipulation, such as in genetic
     * programming, where new program trees or subtrees need to be constructed dynamically based on evolving conditions
     * or operations.
     *
     * ### Example:
     * ```
     * val program: Program = ...
     * val newReducible: Reducible = ...
     * val newChildren: List> = ...
     * val newNode = program.createNode(newReducible, newChildren)
     * // newNode is now a new Program instance with the specified value and children
     * ```
     *
     * @param value The reducible expression to be used as the value of the new node.
     * @param children The list of child `Program` instances to be attached to the new node.
     * @return A new `Program` instance with the given value and children.
     */
    override fun createNode(value: Reducible, children: List>) = copy(value, children)

    /**
     * Evaluates the program by invoking its reducible expression with a specified environment and a set of arguments.
     *
     * This operator function enables the `Program` class to act as an executable entity within a computational context,
     * following the principles of functional programming.
     *
     * ## Functionality:
     * - Applies the reducible expression (`value`) of the program to the given environment and arguments.
     * - For each child in the `children` list, recursively invokes the child program with the same environment and
     *   arguments.
     * - The results of these child invocations are passed as a list of arguments to the parent program's reducible
     *   expression.
     * - Returns the result of evaluating the reducible expression with these arguments.
     *
     * ## Usage:
     * This operator function is critical in scenarios where the program needs to be executed or evaluated,
     * particularly in computational models such as genetic programming, or complex expression evaluations. It allows
     * for the dynamic execution of hierarchical program structures.
     *
     * ### Example:
     * ```
     * val program: Program = ...
     * val environment: Environment = ...
     * val result = program(environment, arg1, arg2, arg3)
     * // result holds the outcome of evaluating the program with the provided arguments
     * ```
     *
     * @param environment The `Environment` in which the program operates.
     * @param args A variable number of arguments of type `V` used in the program's evaluation.
     * @return The result of evaluating the program's reducible expression with the given environment and arguments.
     */
    operator fun invoke(environment: Environment, vararg args: V): V =
        value(environment, children.map { it(environment, *args) })

    /**
     * Creates a copy of the current `Program` instance with optional new value and children.
     *
     * This method provides a way to create a modified version of the program, allowing for adjustments in its
     * reducible expression or its children while retaining the overall structure.
     *
     * ## Functionality:
     * - Allows for specifying a new `Reducible` value and/or a new list of children `Program` instances.
     * - If no new value or children are provided, the method uses the current program's value and children.
     * - Returns a new `Program` instance with the specified or inherited value and children.
     *
     * ## Usage:
     * The `copy` method is particularly useful in scenarios involving program manipulation or transformation, where
     * modifications to parts of the program are required while maintaining the integrity of the rest of the structure.
     * It is a common pattern in immutable or persistent data structures.
     *
     * ### Example:
     * ```
     * val originalProgram: Program = ...
     * val modifiedProgram = originalProgram.copy(
     *     value = newReducibleExpression,
     *     children = newChildrenList
     * )
     * // modifiedProgram is now a new Program instance with updated value and children
     * ```
     *
     * @param value The new reducible expression for the program; defaults to the current program's value if not
     *   specified.
     * @param children The new list of child programs; defaults to the current program's children if not specified.
     * @return A new `Program` instance with the specified or current value and children.
     */
    fun copy(value: Reducible = this.value, children: List> = this.children) = Program(value, children)

    /**
     * Generates a simple string representation of the program. This method overrides the `toSimpleString` method from
     * the `MultiStringFormat` interface and provides a concise view of the program's structure, focusing on the
     * reducible expression and its immediate children.
     *
     * ## Functionality:
     * - Constructs a string representation of the program based on its current state.
     *     - If the program has no children, it returns the string representation of the program's value (reducible
     *       expression).
     *     - If the program has children, it formats the string to include the reducible expression followed by a
     *       space-separated list of its children's string representations, all enclosed in parentheses.
     *
     * ## Usage:
     * This method is useful for debugging, logging, or displaying the program in a human-readable format. It
     * simplifies the visualization of the program's structure, especially in scenarios where a quick overview of the
     * program is needed.
     *
     * ### Example:
     * ```
     * val program: Program = ...
     * val simpleString = program.toSimpleString()
     * // If program has no children, simpleString might be "MyValue"
     * // If program has children, simpleString might be "(MyValue child1 child2 child3)"
     * ```
     *
     * @return A string representation of the program, concisely showing its value and immediate children.
     */
    override fun toSimpleString() = when {
        children.isEmpty() -> value.toString()
        else -> "(${value.toSimpleString()} ${children.joinToString(" ") { it.toString() }})"
    }

    /**
     * Provides a detailed string representation of the `Program` instance. This method overrides the `toString` method
     * from the `Object` class and offers a more informative view of the program, including its value and the values of
     * its immediate children.
     *
     * ## Functionality:
     * - Constructs a detailed string representation of the program.
     * - Includes the program's reducible expression (`value`) and a list of the values of its children.
     * - The children's values are presented in a list format for clarity.
     *
     * ## Usage:
     * This method is particularly useful for obtaining a comprehensive textual representation of the program, which can
     * be helpful in debugging, logging, or displaying the program structure in a detailed manner.
     *
     * ### Example:
     * ```
     * val program: Program = ...
     * val programString = program.toString()
     * // programString might be "Program(value=MyValue, children=[ChildValue1, ChildValue2, ChildValue3])"
     * ```
     *
     * @return A string representation of the program, including its value and the values of its children.
     */
    override fun toString() = "Program(value=$value, children=${children.map { it.value }})"

    /**
     * Generates a comprehensive string representation of the `Program` instance, providing detailed information about
     * the program's structure. This method overrides the `toDetailedString` method from the `MultiStringFormat`
     * interface, offering an in-depth view of the program, including its value and the detailed descriptions of its
     * children.
     *
     * ## Functionality:
     * - Utilizes a `StringBuilder` to construct a detailed string representation.
     * - Starts with the program's basic information, including its reducible expression (`value`) and the list of
     *   children.
     * - Adds a detailed description of the program's own reducible expression.
     * - Iterates through each child, appending a detailed description of each child's value to the string.
     * - Returns the complete string constructed, providing a thorough overview of the program and its children.
     *
     * ## Usage:
     * This method is especially useful for debugging and analysis purposes, where a detailed insight into the program's
     * structure and its components is required. It aids in understanding the intricate details of the program and its
     * sub-components.
     *
     * ### Example:
     * ```
     * val program: Program = ...
     * val detailedString = program.toDetailedString()
     * // detailedString might look like:
     * // "Program(value=MyValue, children=[Child1, Child2])\n  MyValue(detailed)\n  ChildValue1(detailed)\n
     * // ChildValue2(detailed)\n"
     * ```
     *
     * @return A detailed string representation of the program, including its value and a detailed description of its
     *   children.
     */
    override fun toDetailedString(): String {
        val sb = StringBuilder()
        sb.append("Program(value=$value, children=$children)\n")
        sb.append("  ${value.toDetailedString()}\n")
        children.forEach { child ->
            sb.append("  ${child.value.toDetailedString()}\n")
        }
        return sb.toString()
    }

    override fun equals(other: Any?) = when {
        other === this -> true
        other !is Program<*> -> false
        value != other.value -> false
        children != other.children -> false
        else -> false
    }

    override fun hashCode() = Objects.hash(Program::class, value, children)
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy