Hone logo
Hone
Problems

Functional Transformations with Rust's Fn Traits

This challenge focuses on understanding and utilizing Rust's Fn, FnMut, and FnOnce traits. These traits are fundamental to functional programming in Rust, enabling you to treat functions as first-class citizens and pass them around as arguments or return values. Your task is to implement a series of functions that leverage these traits to perform transformations on data.

Problem Description

You are tasked with creating a module named functional_transformations that provides several utility functions centered around applying transformations to collections of data. These transformations will be defined using closures that conform to the Fn, FnMut, or FnOnce traits. The module should include the following functions:

  1. map_fn(data: &[i32], transform: impl Fn(i32) -> i32) -> Vec<i32>: This function takes a slice of i32 integers and a function transform (which is an Fn trait implementation). It applies the transform function to each element of the slice and returns a new Vec<i32> containing the transformed values.

  2. filter_fn(data: &[i32], predicate: impl FnMut(i32) -> bool) -> Vec<i32>: This function takes a slice of i32 integers and a function predicate (which is an FnMut trait implementation). It filters the slice, keeping only the elements for which the predicate function returns true. The filtered elements are returned as a new Vec<i32>.

  3. reduce_fn(data: &[i32], initial_value: i32, accumulator: impl FnOnce(i32, i32) -> i32) -> i32: This function takes a slice of i32 integers, an initial value, and a function accumulator (which is an FnOnce trait implementation). It reduces the slice to a single value by repeatedly applying the accumulator function. The accumulator takes the current accumulated value and the next element from the slice as input and returns the new accumulated value. The final accumulated value is returned.

Examples

Example 1:

Input: data = [1, 2, 3, 4, 5], transform = |x| x * 2
Output: [2, 4, 6, 8, 10]
Explanation: The `transform` function doubles each element of the input slice.

Example 2:

Input: data = [1, 2, 3, 4, 5], predicate = |x| x % 2 == 0
Output: [2, 4]
Explanation: The `predicate` function checks if an element is even. Only even elements are kept.

Example 3:

Input: data = [1, 2, 3, 4, 5], initial_value = 0, accumulator = |acc, x| acc + x
Output: 15
Explanation: The `accumulator` function sums the elements of the slice, starting with the `initial_value`.

Constraints

  • The input data slice will always contain at least zero elements.
  • The transform function in map_fn should not modify the original data.
  • The predicate function in filter_fn should not modify the original data.
  • The accumulator function in reduce_fn should not modify the original data.
  • All input values will be valid i32 integers.
  • Performance is not a primary concern for this challenge, but avoid unnecessarily inefficient implementations.

Notes

  • Pay close attention to the differences between Fn, FnMut, and FnOnce. Fn closures can be called multiple times without capturing any variables by move. FnMut closures can be called multiple times and may capture variables by mutable reference. FnOnce closures can only be called once and may capture variables by move or immutable reference.
  • Consider how the closure's capturing behavior affects which trait it should implement.
  • The reduce_fn function should handle the case where the input slice is empty gracefully (returning the initial_value).
  • The module should be named functional_transformations.
  • The functions should be public.
  • Error handling is not required for this challenge. Assume valid inputs.
Loading editor...
rust