问题描述
如果我可以不时在 Array
和 Map
上使用安全的就地破坏性更新,那将会很有用。线性类型是一种通过将值的消耗限制为 exactly once 语义来允许安全突变的技术。虽然似乎不可能在 Javascript 中实现 exactly once,但这里有一个宽松的最多一次变体的实现,它对应于仿射类型:
class LinearProxy {
constructor() {
this.once = false;
}
get(o,k) {
if (this.once)
throw new TypeError("non-linear type usage");
else this.once = true;
if (k === "run")
return once(f => {
const r = f(o);
if (r === o)
throw new TypeError("non-linear type usage");
else return r;
});
return o[k];
}
set(o,k,v) {
if (this.once)
throw new TypeError("non-linear type usage");
o[k] = v;
return true;
}
}
const linear = o => new Proxy(o,new LinearProxy());
const once = f => {
let called = false;
return x => {
if (called)
throw new TypeError("non-linear type usage");
else {
called = true;
return f(x);
}
};
};
const run = f => tx =>
tx["run"] (f);
const id = x => x;
const last = xs => xs[xs.length - 1];
const dup = xs => [...xs,...xs];
const xs = linear([1,2,3]),ys = linear([1,zs = linear([1,3]);
xs[3] = 4;
xs[4] = 5;
console.log(
"run(last) (xs):",run(last) (xs)); // 5
try {run(last) (xs)}
catch(e) {console.log("run(last) (xs):",e.message)} // type error (A)
try {const x = xs[4]}
catch(e) {console.log("x = xs[4]:",e.message)} // type error (A)
try {xs[0] = 11}
catch(e) {console.log("xs[0] = 11:",e.message)} // type error (B)
try {run(id) (ys)}
catch(e) {console.log("run(id) (ys):",e.message)} // type error (C)
console.log(run(dup) (zs)); // [1,3,1,3] (D)
曾经使用过的线性类型的后续读访问 (A) 和写访问 (B) 会引发类型错误。尝试立即访问线性类型的引用 (C) 也会引发类型错误。后者只是一个简单的检查,以防止意外返回引用。人们很容易绕过它,所以我们必须依靠这种情况的约定。
然而,D
不是仿射的,因为参数被消耗了两次。非线性使用发生在函数范围内这一事实是否意味着它仍然(相对)安全?有没有更聪明的方法在 Javascript 中实现线性类型?
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)