Skip to content

Symmetric RWS Philosophy

> Status: PATCH · 已对齐 PCR Master Blueprint v1.0 > 范畴: 跨子域设计原则(无具体路径) > 参考实现: monad/RWS.hsimulation/pipeline/RWSTypes.hfcc/dsl/FccProgram.h


0. 核心命题

仿真平台的所有"演化机器"都遵循同一抽象:(R, S) → (A, S', W)

  • R(Reader):装配后冻结的环境
  • W(Writer):append-only 日志(Monoid)
  • S(State):可读写的当前状态
  • A:本次计算的返回值

通过把 Dynamics / FCC / Bus / Avionics Device 都统一到 RWS Monad,我们获得:

  1. 接口对称:每一层都看起来一样,认知负担线性而非乘积
  2. 副作用封装:日志、状态变更、信道写入全部走 Monad 语义,main loop 没有"暗动作"
  3. 可测试性:注入 mock R、检查 W、对比 S/S' 即可单测任何层
  4. 并行就绪:每个 BodyRWS 在自己的 (R, S) 上运行,BodyTick 天然可并行(详见 06_Simulation/Dual_Layer_RWS.md §8)

1. 五层 Monad 矩阵(v1.0)

算子描述解释器RWS 实例路径
WorldTick全局编排(time → BodyTick × N → bus_route → topology)sim::world_tickRWS<WorldEnv, WorldState, WorldLog, WorldOut>simulation/pipeline/WorldTick.{h,cpp}
BodyTick单体 5 阶段 pipelinesim::body_tickRWS<BodyEnv, RocketBody, BodyLog, BodyOut>simulation/pipeline/BodyTick.{h,cpp}
FCCFree Monad DSL(8 op)FccInterpreterRWS<FccEnv, FccState, FccLog, FccOutFrame>fcc/dsl/, fcc/interpreter/, fcc/state/
Plant Physicsforce computer 链 + Forces Monoidper-stage compiled pipelineBodyRWS<Forces>plant/physics/{Thrust,Drag,Gravity}.{h,cpp}
Bus语义消息 publish/pollbus::IBusBusLog(Writer 内化)bus/{IBus,BusPayloads}.h

> 关键变化(v1.0): > - v0 把 dynamics 当作"单层 RWS"——v1 改为 WorldRWS + BodyRWS 双层(详见 06_Simulation/Dual_Layer_RWS.md) > - v0 把 FCC 视为另一台独立机器——v1 让 simulation::FccTick(一个跨域适配 stage)把 FCC 嵌入 BodyTick ②(详见 06_Simulation/Body_World_Tick.md §2.2) > - v0 BusMonitor 是独立可观察对象——v1 内化为 BusLog(Writer Monad,详见 Blueprint §7.1)


2. WorldRWS / BodyRWS 双层

2.1 类型签名

cpp
// simulation/pipeline/RWSTypes.h
namespace sim {

template <typename A>
using WorldRWS = monad::RWS<WorldEnv, WorldState, WorldLog, A>;

template <typename A>
using BodyRWS  = monad::RWS<BodyEnv, RocketBody, BodyLog, A>;

} // namespace sim

2.2 降维-演化-升维

WorldRWS::ask  → WorldEnv(全局只读)

       └─ probe::assemble_body_env(world_env, body, t)  ── 降维(per-body 投影)


                  BodyRWS::ask → BodyEnv(局部只读,含 traj/aero/mass_props 私享 ctx)

                       └─ body_tick(dt) 演化 RocketBody


                  BodyOut + BodyLog(出栈)

                       └─ lift_body_log(BodyLog) → WorldLog(升维 Monoid 累加)

WorldRWS::tell ← WorldLog

详见 06_Simulation/Dual_Layer_RWS.md §3 与 06_Simulation/WorldEnv_Assembly.md §4。

2.3 不对称性(v1.0 裁定)

WorldRWS 与 BodyRWS 不对称,这是有意为之:

  • WorldEnv 是全局 universe(atmosphere/gravity/wind/plant_assets/scheduler)
  • BodyEnv 是 per-body 局部 context(含 traj/aero/mass_props 三个私享 ctx + WorldEnv 引用)

强行让两者对称(如"WorldEnv 也持有 traj_ctx")会破坏 N-body 独立性。


3. FCC:Free Monad → RWS

3.1 算子分离

FCC 的算法(导航/制导/控制)是纯函数,不该被 RWS 语义污染。设计上:

  • 算子层(DSL)Free<FccOp, A>,仅 8 个 I/O 算子(ReadIMU/GetTime/GetEnv/GetState/UpdateState/OutputControls/WriteTelemetry/LogMessage)
  • 算法层:纯 C++ 函数,Nav(FccState) → NavOutputGuidance(...) → GuidanceOutputControl(...) → ControlOutput
  • 解释器层FccInterpreter 把 Free Monad tree → RWS<FccEnv, FccState, FccLog, A>
cpp
// fcc/dsl/FccProgram.h —— 纯算子描述(与硬件无关)
FccProgram ascent_program =
      read_imu()
    >>= [](Imu imu) {
        return get_state() >>= [imu](FccState s) {
            auto nav   = run_nav_algorithm(imu, s);        // 纯函数
            auto guide = run_guidance_algorithm(nav, s);   // 纯函数
            auto ctrl  = run_control_algorithm(guide, s);  // 纯函数
            return update_state(s.with(nav, guide, ctrl))
                 >> output_controls(ctrl);
        };
    };

// fcc/interpreter/FccInterpreter.cpp —— 把算子 tree 翻译成 RWS 动作
auto fcc_rws = FccInterpreter::run(ascent_program);
auto [out, new_state, log] = fcc_rws.run(fcc_env, current_state);

3.2 与 simulation 的契约

FCC 被嵌入 BodyTick ② 阶段,由 simulation::FccTick(一个 stage 算子)调用:

BodyTick ② FccTick:
  bus → FccInFrame (decode)

  fcc::tick(in_frame, dt)
  ├─ Free Monad tree(mission 编译产物,per-stage 预编译)
  ├─ Interpreter 翻译
  └─ RWS<FccEnv, FccState, FccLog> 执行

  FccOutFrame → bus (encode)

详见 04_FCC/Free_Monad_DSL.md04_FCC/Interpreter_and_RWS.md04_FCC/Pipeline_Factory_and_Compilation.md04_FCC/FCC_State_Machine.md

3.3 v0 → v1 关键修正

  • v0 的 FccCore.cpp 内置一个"主循环 scheduler"——v1 删除,scheduler 移到 simulation::MultiRateScheduler(Runner 持有)
  • v0 把 GNC 算法写进 FccInterpreter::operator() lambda 里——v1 移到 fcc/algorithms/(详见 08_Cross_Cutting/Algorithm_Integration_Guide.md

4. Plant Physics:Forces Monoid

4.1 设计

force computer 是 BodyRWS 算子,不是独立 RWS。多个 force computer 通过 Forces Monoid 累加:

cpp
// plant/physics/Thrust.h
BodyRWS<Forces> compute_thrust_contribution(const std::vector<EngineEffect>&);

// plant/physics/Drag.h
BodyRWS<Forces> compute_aero_contribution(const DynInFrame&);

// plant/physics/Gravity.h
BodyRWS<Forces> compute_gravity_contribution();

// 组合:Monoid 加法
auto all_forces =
      compute_thrust_contribution(effects)
    | [&](Forces f1) { return compute_aero_contribution(in) | [f1](Forces f2) { return body_pure(f1 + f2); }; }
    | [&](Forces f12) { return compute_gravity_contribution() | [f12](Forces f3) { return body_pure(f12 + f3); }; };

详见 05_Dynamics_Core/Forces_Monoid.md

4.2 Per-stage 预编译

force computer 的组合在装配期完成(per WorldStage 一份);运行期 BodyTick 通过 compiled_dynamics.per_stage[body.world_stage] 直接派发(O(1))。

详见 05_Dynamics_Core/Topology_Algebra.md04_FCC/Pipeline_Factory_and_Compilation.md


5. Bus:Writer 内化

BusMonitor 是独立的可观察对象,违背 RWS 纯性。v1 把它内化进 BusLog

cpp
class IBus {
public:
    virtual void publish(const BusMessage&) = 0;
    virtual std::vector<BusMessage> poll(BusAddr) = 0;
};

// 实现持有 BusLog Writer(每次 publish/poll 追加 trace)
class InMemoryBus : public IBus {
private:
    BusLog log_;
public:
    BusLog flush_log();  // 由 BodyTick 末尾调用,并入 BodyLog
};

详见 03_Avionics_and_Bus/Semantic_Bus_Pattern.md 与 Blueprint §7.1。


6. 三种 Monad 的协同时序

runtime::Runner::run():
    while (t < end):
        world_tick(dt).run(world_env, world_state)

        └─ WorldRWS<WorldOut>

            ├─ A. 时间推进 (WorldState mutation)

            ├─ B. for each body:
            │     ├─ probe → BodyEnv
            │     └─ body_tick(dt).run(body_env, body)
            │         │
            │         └─ BodyRWS<BodyOut>
            │             ├─ ① Avionics step
            │             ├─ ② FCC tick:
            │             │    fcc.tick(in, dt).run(fcc_env, fcc_state)
            │             │    └─ FccRWS<FccOutFrame>(pure Layer-3)
            │             ├─ ③ Plant Physics(per-stage compiled)
            │             ├─ ④ Dynamics integrate
            │             └─ ⑤ DynOutFrame 封装

            ├─ C. Bus 路由 (IBus + BusLog 内化)

            └─ D. 事件解释 + 拓扑演化
                  ws.bodies = evolve_topology(...)

7. 好处汇总

收益机制
确定性(R, S) → (A, S', W) 函数式语义
可组合性>>= / | 把小算子拼大 pipeline
可调试性Writer 记录完整决策历史
可热替换Free Monad 让 FCC 策略可在运行期切换(不改解释器)
可并行BodyRWS 各自独立 (R, S),BodyTick 天然多线程
HIL 透明信道实现替换不动 Monad 骨架

8. 反模式

反模式后果正确做法
把日志写 stdout / 直接写文件不可测、不可重定向、违 RWS 纯性Writer Monad tell(log);Runner 末尾统一落盘
在算子内修改 WorldEnvReader 语义破坏;并行不安全WorldEnv 装配后冻结
BodyTick 内修改 WorldState破坏并行合法性 5 条件事件出栈到 BodyOut.emitted_events,World 末尾串行应用
在 FCC Interpreter 里嵌算法算法与解释器耦合;不可热替换算法纯函数 in fcc/algorithms/,Interpreter 仅 dispatch
BusMonitor 持有独立 ptr,main loop 拉数据与 Writer 重复;线程安全噩梦BusLog 内化
Dynamics 单层 RWS(直接 WorldState → Forces多 body 无法独立并行;环境冻结策略不清晰WorldRWS + BodyRWS 双层(v1.0 必须)

9. C-Distillation 路径

C++ Monad 抽象C 蜕化
WorldRWS<A>::run(env, state)int world_tick_c(const WorldEnv*, WorldState*, WorldLog*, WorldOut*, Time)
BodyRWS<A>::run(env, body)int body_tick_c(const BodyEnv*, RocketBody*, BodyLog*, BodyOut*, Time)
>>= / |顺序 C 函数调用(编译器内联)
Free<FccOp> treeswitch-case 解释器(编译期 inline)
Writer Monad +=数组 append + 计数累加
Reader Monad askconst struct* 直接读

详见 09_Cross_Cutting/C_Distillation.md(待写)。


10. 引用

  • Blueprint §2.6(Simulation:跨域绑定层)、§2.6.4(双层 RWS 实例化)、§3.1(FCC 三层架构)、§7.1(Bus 内化 Writer)
  • 06_Simulation/Dual_Layer_RWS.md(WorldRWS + BodyRWS 详细定义)
  • 04_FCC/Free_Monad_DSL.md(FCC 算子层)
  • 04_FCC/Interpreter_and_RWS.md(解释器把 DSL 翻译成 RWS)
  • 04_FCC/Pipeline_Factory_and_Compilation.md(per-stage 编译)
  • 05_Dynamics_Core/Forces_Monoid.md(Forces Monoid 累加)
  • 01_Foundation/Monad_Toolkit.md(RWS 模板实现)