Skip to content

Monad Toolkit

> Status: PATCH · 已对齐 PCR Master Blueprint v1.0 > 范畴: src/monad/{RWS.h, Free.h, Pipeline.h}src/types/monad/ (legacy 位置,Wave 0 内迁出)

The "Haskell in C++" toolkit. This document defines the Monad templates, pipeline operators, and utility combinators that power the RWS and Free Monad implementations.

0. v1.0 命名 / 路径裁定

  • 顶层命名空间 monad::(不是 util::monad::
  • 物理路径:src/monad/{RWS.h, Free.h, Pipeline.h} (Wave 0 之前 v0 临时位置为 src/types/monad/
  • 不依赖任何业务子域(plant/fcc/...)
  • Pipeline 别名定义在 simulation/pipeline/RWSTypes.h
    cpp
    namespace sim {
        template <typename A> using WorldRWS = monad::RWS<WorldEnv, WorldState, WorldLog, A>;
        template <typename A> using BodyRWS  = monad::RWS<BodyEnv, RocketBody, BodyLog, A>;
    }
    详见 06_Simulation/Dual_Layer_RWS.md §2。

1. RWS Monad (Reader-Writer-State)

The core mechanism for both Dynamics and FCC computations.

  • R: Environment (Read-only config)
  • S: State (Read-write context)
  • W: Log (Append-only output, must be Monoid)
  • A: Result type

> v1.0 模板参数顺序裁定RWS<R, S, W, A>(State 在 Writer 之前)。理由:与 body_tick / world_tick 等动作的 .run(env, state) 顺序匹配。

cpp
// src/monad/RWS.h
namespace monad {

#include <functional>
#include <tuple>
#include <vector>

template <typename R, typename S, typename W, typename A>
class RWS {
public:
    // The core computation: (R, S) -> (A, S, W)
    using Computation = std::function<std::tuple<A, S, W>(const R&, S)>;

    Computation run;

    // --- Constructor ---
    explicit RWS(Computation c) : run(std::move(c)) {}

    // --- Core Operations ---
    
    // Pure / Return
    static RWS pure(A val) {
        return RWS([val](const R&, S s) {
            return std::make_tuple(val, s, W{});
        });
    }

    // FlatMap / Bind (>>=)
    template <typename B>
    RWS<R, S, W, B> flatMap(std::function<RWS<R, S, W, B>(A)> f) const {
        return RWS<R, S, W, B>([this, f](const R& r, S s) {
            auto [a, s1, w1] = this->run(r, s);
            auto [b, s2, w2] = f(a).run(r, s1);
            return std::make_tuple(b, s2, w1 + w2); // Monoid accumulation
        });
    }
    
    // Functor Map
    template <typename B>
    RWS<R, S, W, B> map(std::function<B(A)> f) const {
        return flatMap<B>([f](A a) { return RWS<R, S, W, B>::pure(f(a)); });
    }
};

// --- RWS Primitives ---

// Read Environment
template <typename R, typename S, typename W>
RWS<R, S, W, R> ask() {
    return RWS<R, S, W, R>([](const R& r, S s) {
        return std::make_tuple(r, s, W{});
    });
}

// Get State
template <typename R, typename S, typename W>
RWS<R, S, W, S> get() {
    return RWS<R, S, W, S>([](const R&, S s) {
        return std::make_tuple(s, s, W{});
    });
}

// Set State
template <typename R, typename S, typename W>
RWS<R, S, W, std::monostate> put(S new_state) {
    return RWS<R, S, W, std::monostate>([new_state](const R&, S) {
        return std::make_tuple(std::monostate{}, new_state, W{});
    });
}

// Modify State
template <typename R, typename S, typename W>
RWS<R, S, W, std::monostate> modify(std::function<S(S)> f) {
    return RWS<R, S, W, std::monostate>([f](const R&, S s) {
        return std::make_tuple(std::monostate{}, f(s), W{});
    });
}

// Write Log
template <typename R, typename S, typename W>
RWS<R, S, W, std::monostate> tell(W log) {
    return RWS<R, S, W, std::monostate>([log](const R&, S s) {
        return std::make_tuple(std::monostate{}, s, log);
    });
}

} // namespace monad

> Monoid 律要求W 必须满足结合律 (a + b) + c == a + (b + c) 与单位元 W{}。详见 05_Dynamics_Core/Forces_Monoid.md §3 与 06_Simulation/Body_World_Tick.md §4。

2. Pipeline Operators

Syntactic sugar to eliminate callback hell.

Operator >>= (Bind)

Standard Haskell bind.

cpp
namespace monad {

template <typename R, typename S, typename W, typename A, typename F>
auto operator>>=(const RWS<R, S, W, A>& m, F&& f) {
    return m.flatMap(std::forward<F>(f));
}

// Operator `|`: F# style pipe (alternative spelling)
template <typename R, typename S, typename W, typename A, typename F>
auto operator|(const RWS<R, S, W, A>& m, F&& f) {
    return m.flatMap(std::forward<F>(f));
}

// Operator `>>`: discard left value
template <typename R, typename S, typename W, typename A, typename B>
auto operator>>(const RWS<R, S, W, A>& m, const RWS<R, S, W, B>& n) {
    return m.template flatMap<B>([n](A) { return n; });
}

} // namespace monad

3. Free Monad

For FCC algebraic descriptions(详见 04_FCC/Free_Monad_DSL.md):

cpp
// src/monad/Free.h
namespace monad {

template <typename F, typename A>
class Free {
    // Pure A | Impure F<Free<F, A>>
    std::variant<Pure<A>, Impure<F, A>> data_;

public:
    static Free pure(A val);

    template <typename B>
    Free<F, B> flatMap(std::function<Free<F, B>(A)> f) const;

    template <typename Interpreter>
    auto fold(Interpreter& interp) const;   // 用 interpreter 把 Free 翻译成具体 Monad
};

} // namespace monad

详细应用见 04_FCC/Free_Monad_DSL.md04_FCC/Interpreter_and_RWS.md

4. Combinators

Utilities for composing Monadic actions.

cpp
namespace monad {

// Sequence: Run a list of actions in order
template <typename R, typename S, typename W, typename A>
RWS<R, S, W, std::vector<A>> sequence(const std::vector<RWS<R, S, W, A>>& actions);

// When: Run action if condition is true
template <typename R, typename S, typename W>
RWS<R, S, W, std::monostate> when(bool condition, RWS<R, S, W, std::monostate> action) {
    if (condition) return action;
    return RWS<R, S, W, std::monostate>::pure({});
}

} // namespace monad

5. Usage Example: Body Physics Pipeline

cpp
using namespace monad;
using sim::BodyRWS;

auto plant_physics_stage =
      ask<BodyEnv, RocketBody, BodyLog>()
    >>= [](const BodyEnv& env) {
        return get<BodyEnv, RocketBody, BodyLog>()
            >>= [&env](RocketBody body) {
                auto thrust  = plant::compute_thrust_contribution(body.engine_effects);
                auto drag    = plant::compute_aero_contribution(body.dyn_in);
                auto gravity = plant::compute_gravity_contribution();
                return (thrust >> drag >> gravity);    // Forces Monoid 累加
            };
    };

详见 05_Dynamics_Core/Forces_Monoid.md §4 与 06_Simulation/Body_World_Tick.md §2.2 ③。

6. C-Distillation 路径

C++ MonadC 蜕化
RWS<R, S, W, A>::run(env, state)普通函数 int compute(const R*, S*, W*, A*),编译器内联
>>= / | / >>顺序 C 函数调用
Free<F, A>switch-case 解释器(无 heap)
std::function<...> Computation 包装内联 lambda 或函数指针
std::tuple 返回多 out-parameter 或 struct 返回

详见 08_Cross_Cutting/Implementation_Roadmap.md §7(C-Distillation Roadmap)。

7. 引用

  • Blueprint §2.5(dynamics_core)、§2.6(simulation)、§3.1(FCC 三层架构)、§7.12(C-Distillation)
  • 06_Simulation/Dual_Layer_RWS.md(WorldRWS / BodyRWS 别名)
  • 04_FCC/Free_Monad_DSL.md(Free Monad 用例)
  • 08_Cross_Cutting/Symmetric_RWS_Philosophy.md(设计哲学)