Back

pipe

Overview

The pipe function enables functional composition by allowing multiple operations to be chained together into a single processing pipeline. It provides a clean, readable way to express complex transformations on Series.

Function Signatures


          // Base case: end of pipe chain
          template <typename T>
          auto pipe(T&& value);
          
          // General case: pipe with operation
          template <typename T, typename F, typename... Rest>
          auto pipe(T&& value, F&& operation, Rest&&... rest);
          
          // Operator | overload for pipe operations
          template <typename T, typename F>
          auto operator|(T&& value, F&& operation);
          
          // make_pipe factory function
          template <typename... F>
          auto make_pipe(F&&... operations);
        

Parameters

Parameter Type Description
value T&& (any type) The input value to be processed through the pipeline.
operation F&& (callable) A function or operation to apply to the value. Should accept the input value and return a transformed value.
rest Rest&&... (callables) Additional operations to be applied in sequence.

Return Value

The result of applying all operations in sequence to the input value.

Example Usage

Basic Pipe Example

// Create a Serie
df::Serie<int> numbers{1, 2, 3, 4, 5};

// Using pipe function with multiple operations
auto result = df::pipe(
    numbers,
    [](const df::Serie<int>& s) { return s.map([](int x, size_t) { return x * 2; }); },
    [](const df::Serie<int>& s) { return s.map([](int x, size_t) { return x + 10; }); }
);  // {12, 14, 16, 18, 20}

// Using the | operator (more readable)
auto piped_result = numbers
    | [](const df::Serie<int>& s) { return s.map([](int x, size_t) { return x * 2; }); }
    | [](const df::Serie<int>& s) { return s.map([](int x, size_t) { return x + 10; }); };
// {12, 14, 16, 18, 20}
Using Bind Functions

// Create a Serie
df::Serie<double> values{1.1, 2.2, 3.3, 4.4, 5.5};

// Using bind functions with the pipe operator
auto result = values
    | df::bind_map([](double x, size_t) { return x * 2; })       // Double each value
    | df::bind_map([](double x, size_t) { return std::round(x); })  // Round to nearest integer
    | df::bind_map([](double x, size_t) { return x > 8; });      // Convert to boolean
// {false, false, true, true, true}

// Create a custom bind function
auto double_values = [](const df::Serie<double>& s) {
    return s.map([](double x, size_t) { return x * 2; });
};

// Use it in a pipe
auto doubled = values | double_values;  // {2.2, 4.4, 6.6, 8.8, 11.0}
Creating Reusable Pipelines

// Create a reusable pipeline using make_pipe
auto process_values = df::make_pipe(
    df::bind_map([](double x, size_t) { return x * 2; }),       // Double
    df::bind_map([](double x, size_t) { return x + 10; }),      // Add 10
    df::bind_map([](double x, size_t) { return std::round(x); })  // Round
);

// Apply the pipeline to different Series
df::Serie<double> values1{1.1, 2.2, 3.3};
df::Serie<double> values2{4.4, 5.5, 6.6};

auto result1 = process_values(values1);  // {12, 14, 17}
auto result2 = process_values(values2);  // {19, 21, 23}

// Combine multiple operations
auto preprocess = df::bind_map([](double x, size_t) { return std::abs(x); });
auto calculate = df::bind_map([](double x, size_t) { return std::sqrt(x); });
auto format = df::bind_map([](double x, size_t) { return std::round(x * 100) / 100; });

// Create a pipeline with all operations
auto analyze = df::make_pipe(preprocess, calculate, format);

// Apply the combined pipeline
df::Serie<double> input{-16.0, 25.0, -4.0, 9.0};
auto output = analyze(input);  // {4.0, 5.0, 2.0, 3.0}
Complex Transformation Pipeline

// Process student data
df::Serie<std::string> names{"Alice Smith", "Bob Johnson", "Charlie Brown"};
df::Serie<double> scores{87.5, 92.0, 78.5};

// Create a pipeline to generate formatted reports
auto report_pipeline = df::make_pipe(
    // Combine name and score into a tuple
    [](const df::Serie<std::string>& names, const df::Serie<double>& scores) {
        return df::zip(names, scores);
    },
    
    // Format each student record
    df::bind_map([](const auto& tuple, size_t index) {
        auto [name, score] = tuple;
        std::string grade;
        
        if (score >= 90) grade = "A";
        else if (score >= 80) grade = "B";
        else if (score >= 70) grade = "C";
        else grade = "D";
        
        return "Student #" + std::to_string(index + 1) + ": " + name +
               " - Score: " + std::to_string(score) +
               " - Grade: " + grade;
    })
);

// Apply the pipeline
auto reports = report_pipeline(names, scores);
// {"Student #1: Alice Smith - Score: 87.5 - Grade: B",
//  "Student #2: Bob Johnson - Score: 92.0 - Grade: A",
//  "Student #3: Charlie Brown - Score: 78.5 - Grade: C"}

Implementation Notes

  • The pipe function and | operator both execute operations from left to right.
  • Each operation must accept the result of the previous operation as its input.
  • The make_pipe function creates a reusable pipeline that can be applied to different inputs.
  • Bind functions (e.g., bind_map, bind_forEach) are designed to work seamlessly with pipe.
  • Pipe operations are evaluated lazily, meaning they are only executed when needed.