如何从多个嵌套函数中丢弃分隔的延续?
How to discard a delimited continuation from within multiple nested functions?
我研究定界延续,目前正在尝试丢弃它们以获得类似于引发异常的效果。
这是给我带来麻烦的原因:
const structure = type => cons => {
const f = (f, args) =>
({["run" + type]: f, [Symbol.toStringTag]: type, [Symbol("args")]: args});
return cons(f);
};
const Cont = structure("Cont")
(Cont => f => Cont(f));
const runCont = tf => k =>
tf.runCont(k);
const reset = tf =>
of(tf.runCont(id));
const shift = f =>
Cont(k => f(k).runCont(id));
const of = x =>
Cont(k => k(x));
const liftM2 = f => tf => tg =>
of(runCont(tf) (x => runCont(tg) (y => f(x) (y))));
const id = x => x;
const mulM = liftM2(x => y => x * y);
const addM = liftM2(x => y => x + y);
const subM = liftM2(x => y => x - y);
const z1 = mulM(of(5))
(reset
(addM
(shift(k => of(3)))
(of(3)))
).runCont(id); // 5 * 3 = 15 (as expected)
const z2 = mulM(of(5))
(reset // A
(mulM // B
(addM
(shift(k => of(3))) // C should unwind up to A instead of B
(of(3)))
(of(4)))
).runCont(id); // 5 * 3 * 4 = 60 (but 15 expected)
console.log(z1);
console.log(z2);
看来我只能将堆栈展开一帧。这是 shift
/reset
的设计还是我的实现中的缺陷造成的?
[编辑]
我在 Haskell 中使用它,即它是一个实施问题:
reset :: ((a -> a) -> a) -> (a -> r) -> r
reset k f = f $ k id
shift :: ((a -> r) -> (r -> r) -> r) -> (a -> r) -> r
shift f k = f k id
return :: a -> (a -> r) -> r
return a k = k a
liftM2 :: (a -> b -> c) -> ((a -> r) -> r) -> ((b -> r) -> r) -> (c -> r) -> r
liftM2 f ma mb k = ma $ \a -> mb $ \b -> k (f a b)
example :: Num a => (a -> r) -> r
example = liftM2 (*) (return 5) (reset (liftM2 (*) (return 3) (liftM2 (+) (return 2) (shift (\k -> return 3)))))
我觉得你的liftM2
坏了,因为它不懒惰。而不是使用 of
,它应该构造一个新的延续:
const liftM2 = f => tf => tg =>
Cont(k => runCont(tf) (x => runCont(tg) (y => k(f(x)(y)))));
我研究定界延续,目前正在尝试丢弃它们以获得类似于引发异常的效果。
这是给我带来麻烦的原因:
const structure = type => cons => {
const f = (f, args) =>
({["run" + type]: f, [Symbol.toStringTag]: type, [Symbol("args")]: args});
return cons(f);
};
const Cont = structure("Cont")
(Cont => f => Cont(f));
const runCont = tf => k =>
tf.runCont(k);
const reset = tf =>
of(tf.runCont(id));
const shift = f =>
Cont(k => f(k).runCont(id));
const of = x =>
Cont(k => k(x));
const liftM2 = f => tf => tg =>
of(runCont(tf) (x => runCont(tg) (y => f(x) (y))));
const id = x => x;
const mulM = liftM2(x => y => x * y);
const addM = liftM2(x => y => x + y);
const subM = liftM2(x => y => x - y);
const z1 = mulM(of(5))
(reset
(addM
(shift(k => of(3)))
(of(3)))
).runCont(id); // 5 * 3 = 15 (as expected)
const z2 = mulM(of(5))
(reset // A
(mulM // B
(addM
(shift(k => of(3))) // C should unwind up to A instead of B
(of(3)))
(of(4)))
).runCont(id); // 5 * 3 * 4 = 60 (but 15 expected)
console.log(z1);
console.log(z2);
看来我只能将堆栈展开一帧。这是 shift
/reset
的设计还是我的实现中的缺陷造成的?
[编辑]
我在 Haskell 中使用它,即它是一个实施问题:
reset :: ((a -> a) -> a) -> (a -> r) -> r
reset k f = f $ k id
shift :: ((a -> r) -> (r -> r) -> r) -> (a -> r) -> r
shift f k = f k id
return :: a -> (a -> r) -> r
return a k = k a
liftM2 :: (a -> b -> c) -> ((a -> r) -> r) -> ((b -> r) -> r) -> (c -> r) -> r
liftM2 f ma mb k = ma $ \a -> mb $ \b -> k (f a b)
example :: Num a => (a -> r) -> r
example = liftM2 (*) (return 5) (reset (liftM2 (*) (return 3) (liftM2 (+) (return 2) (shift (\k -> return 3)))))
我觉得你的liftM2
坏了,因为它不懒惰。而不是使用 of
,它应该构造一个新的延续:
const liftM2 = f => tf => tg =>
Cont(k => runCont(tf) (x => runCont(tg) (y => k(f(x)(y)))));