假设我有一个不可变的包装器:
如果我有一个不可变的
所以如果
现在,如果
假设我有一个
甚至可以使用代数语法,伪代码如下:
让我们将操作链接在一起,以满足需要。
template<class T>
struct immut {
T const& get() const {return *state;}
immut modify( std::function<T(T)> f ) const { return immut{f(*state)}; }
immut(T in):state(std::make_shared<T>(std::move(in))){}
private:
std::shared_ptr<T const> state;
};
如果我有一个不可变的
immut<Bob> b
,我可以将Bob(Bob)
操作转换为能够替换我的b
的内容。template<class T>
std::function<immut<T>(immut<T>)> on_immut( std::function<void(T&)> f ){
return [=](auto&&in){ return in.modify( [&](auto t){ f(t); return t; } ); };
}
所以如果
Bob
是int x,y;
,我可以将朴素的可变代码[](auto& b){ b.x++; }
转换为immut<Bob>
更新器。
现在,如果
Bob
反过来有immut<Alice>
成员,而这些成员又有immut<Charlie>
成员。假设我有一个
Charlie
更新器,void(Charlie&)
。我知道我想要更新的Charlie
在哪里。在可变的世界里,它看起来像:void update( Bob& b ){
modify_charlie(b.a.c[77]);
}
我可能会将其拆分为以下几部分:
template<class S, class M>
using get=std::function<M&(S&)>;
template<class X>
using update=std::function<void(X&)>;
template<class X>
using produce=std::function<X&()>;
void update( produce<Bob> b, get<Bob, Alice> a, get<Alice, Charlie> c, update<Charlie> u ){
u(c(a(b())));
}
甚至可以使用代数语法,伪代码如下:
get<A,C> operator|(get<A,B>,get<B,C>);
update<A> operator|(get<A,B>,update<B>);
produce<B> operator|(produce<A>,get<A,B>);
void operator|(produce<A>, update<A>);
让我们将操作链接在一起,以满足需要。
void update( produce<Bob> b, get<Bob, Alice> a, get<Alice, Charlie> c, update<Charlie> u ){std::
u(c(a(b())));
}
变成
b|a|c|u;
这里的步骤可以随时拼接在一起。
使用不可变数据结构,相应的等价物是什么?有没有一个名字?理想情况下,我希望步骤与可变情况下一样隔离但又可组合,在可变状态结构上具有天真的“叶代码”。