Hone logo
Hone
Problems

Functional Composition with pipe()

Functional composition is a technique where the result of one function is passed as the argument to the next, creating a chain of operations. This problem challenges you to implement a pipe() utility function, a fundamental tool in functional programming that enhances code readability and reusability by allowing you to combine multiple functions into a single, cohesive operation that processes data from left to right.

Problem Description

Your task is to implement a pipe() function. This function should accept an arbitrary number of functions as arguments and return a new function. The returned function, when invoked with an initial value, should apply each of the input functions sequentially, from left to right. The output of each function must become the input of the next function in the sequence.

Key Requirements:

  1. The pipe() function itself does not execute the functions; it returns a new function.
  2. The returned function will take one argument (the initial value) and apply the chained operations.
  3. Each function passed to pipe() is expected to be a unary function (accepting a single argument).
  4. The order of execution must be strictly left-to-right.
  5. Consider the edge cases:
    • If pipe() is called with no functions, the returned function should simply return its input value unchanged.
    • If pipe() is called with a single function, the returned function should behave identically to that single function.

Examples

Example 1: Numeric Transformations

// Define some simple unary functions
FUNCTION addOne(x)
  RETURN x + 1
END FUNCTION

FUNCTION multiplyByTwo(x)
  RETURN x * 2
END FUNCTION

FUNCTION subtractThree(x)
  RETURN x - 3
END FUNCTION

// Create a piped function
LET transformNumber = pipe(addOne, multiplyByTwo, subtractThree)

// Apply the piped function
Input: transformNumber(5)
Output: 9
Explanation:
1.  Initial value: 5
2.  addOne(5) -> 6
3.  multiplyByTwo(6) -> 12
4.  subtractThree(12) -> 9

Example 2: String Manipulations

// Define some string manipulation functions
FUNCTION trimString(str)
  RETURN str.trim() // Removes leading/trailing whitespace
END FUNCTION

FUNCTION toUpperCase(str)
  RETURN str.toUpperCase()
END FUNCTION

FUNCTION addExclamation(str)
  RETURN str + "!"
END FUNCTION

// Create a piped function
LET formatMessage = pipe(trimString, toUpperCase, addExclamation)

// Apply the piped function
Input: formatMessage("  hello world  ")
Output: "HELLO WORLD!"
Explanation:
1.  Initial value: "  hello world  "
2.  trimString("  hello world  ") -> "hello world"
3.  toUpperCase("hello world") -> "HELLO WORLD"
4.  addExclamation("HELLO WORLD") -> "HELLO WORLD!"

Example 3: Edge Case - No Functions

// Create a piped function with no operations
LET identityPipe = pipe()

// Apply the piped function
Input: identityPipe(100)
Output: 100
Explanation: No functions were provided to `pipe`, so the returned function simply returns its input as is.

Constraints

  • The number of functions passed to pipe() will be between 0 and 100.
  • Each function passed to pipe() is guaranteed to be a pure function that accepts exactly one argument and returns a single value.
  • The pipe() function should be language-agnostic, focusing on the conceptual implementation.
  • The implementation should be reasonably efficient; avoid excessive overhead for a large number of functions.

Notes

  • Consider how you would accumulate the result of each function application. Techniques like iteration or higher-order functions (e.g., reduce in many languages) are very well-suited for this problem.
  • Remember that pipe() returns a function, and that returned function is what actually performs the computation when called later with an initial value.
  • While not strictly required for this problem, in real-world scenarios, functions used in pipe (and other functional composition utilities) are ideally pure (no side effects) and deterministic (same input, same output). This makes them easier to reason about and test.
Loading editor...
plaintext