mirror of
https://github.com/corda/corda.git
synced 2025-01-06 05:04:20 +00:00
quick sketch of composable continuation implementation
I've been told by knowledgeable people that it is impossible to implement composable continuations (AKA delimited continuations AKA shift/reset) in terms of call-with-current-continuation. Since I don't yet understand why that is, I figured it would help my understanding to attempt it and see how it fails.
This commit is contained in:
parent
c5012cda72
commit
91e4d2b4a1
@ -120,6 +120,8 @@ import java.util.concurrent.Callable;
|
|||||||
public class Continuations {
|
public class Continuations {
|
||||||
private Continuations() { }
|
private Continuations() { }
|
||||||
|
|
||||||
|
private static final ThreadLocal<Reset> latestReset = new ThreadLocal();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Captures the current continuation, passing a reference to the
|
* Captures the current continuation, passing a reference to the
|
||||||
* specified receiver.
|
* specified receiver.
|
||||||
@ -181,6 +183,76 @@ public class Continuations {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static <T> T reset(final Callable<T> thunk) throws Exception {
|
||||||
|
final Reset reset = new Reset(latestReset.get());
|
||||||
|
latestReset.set(reset);
|
||||||
|
try {
|
||||||
|
T result = callWithCurrentContinuation
|
||||||
|
(new CallbackReceiver<T>() {
|
||||||
|
public T receive(Callback<T> continuation) throws Exception {
|
||||||
|
reset.continuation = continuation;
|
||||||
|
return thunk.call();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (reset.continuation != null) {
|
||||||
|
reset.continuation.handleResult(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
} finally {
|
||||||
|
latestReset.set(reset.next);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <Result, Argument> Result shift
|
||||||
|
(final FunctionReceiver<Result, Argument> receiver)
|
||||||
|
throws Exception
|
||||||
|
{
|
||||||
|
return (Result) callWithCurrentContinuation(new CallbackReceiver() {
|
||||||
|
public Object receive(final Callback continuation) {
|
||||||
|
final Reset reset = latestReset.get();
|
||||||
|
final Callback resetContinuation = reset.continuation;
|
||||||
|
reset.continuation = new Callback() {
|
||||||
|
public void handleResult(Object ignored) {
|
||||||
|
try {
|
||||||
|
resetContinuation.handleResult
|
||||||
|
(receiver.receive
|
||||||
|
(new Function() {
|
||||||
|
public Object call(final Object argument)
|
||||||
|
throws Exception {
|
||||||
|
Object result = callWithCurrentContinuation
|
||||||
|
(new CallbackReceiver() {
|
||||||
|
public Object receive
|
||||||
|
(Callback shiftContinuation)
|
||||||
|
throws Exception
|
||||||
|
{
|
||||||
|
reset.continuation = shiftContinuation;
|
||||||
|
continuation.handleResult(argument);
|
||||||
|
throw new AssertionError();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
reset.continuation = null;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
} catch (Exception e) {
|
||||||
|
resetContinuation.handleException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void handleException(Throwable exception) {
|
||||||
|
throw new AssertionError();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
resetContinuation.handleResult(null);
|
||||||
|
throw new AssertionError();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private static native UnwindResult dynamicWind2(Runnable before,
|
private static native UnwindResult dynamicWind2(Runnable before,
|
||||||
Callable thunk,
|
Callable thunk,
|
||||||
Runnable after)
|
Runnable after)
|
||||||
@ -235,4 +307,13 @@ public class Continuations {
|
|||||||
this.exception = exception;
|
this.exception = exception;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static class Reset {
|
||||||
|
public Callback continuation;
|
||||||
|
public final Reset next;
|
||||||
|
|
||||||
|
public Reset(Reset next) {
|
||||||
|
this.next = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
15
classpath/avian/Function.java
Normal file
15
classpath/avian/Function.java
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
/* Copyright (c) 2008-2013, Avian Contributors
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software
|
||||||
|
for any purpose with or without fee is hereby granted, provided
|
||||||
|
that the above copyright notice and this permission notice appear
|
||||||
|
in all copies.
|
||||||
|
|
||||||
|
There is NO WARRANTY for this software. See license.txt for
|
||||||
|
details. */
|
||||||
|
|
||||||
|
package avian;
|
||||||
|
|
||||||
|
public interface Function<Argument, Result> {
|
||||||
|
public Result call(Argument argument) throws Exception;
|
||||||
|
}
|
15
classpath/avian/FunctionReceiver.java
Normal file
15
classpath/avian/FunctionReceiver.java
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
/* Copyright (c) 2008-2013, Avian Contributors
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software
|
||||||
|
for any purpose with or without fee is hereby granted, provided
|
||||||
|
that the above copyright notice and this permission notice appear
|
||||||
|
in all copies.
|
||||||
|
|
||||||
|
There is NO WARRANTY for this software. See license.txt for
|
||||||
|
details. */
|
||||||
|
|
||||||
|
package avian;
|
||||||
|
|
||||||
|
public interface FunctionReceiver<Argument, Result> {
|
||||||
|
public Result receive(Function<Argument, Result> function) throws Exception;
|
||||||
|
}
|
1
makefile
1
makefile
@ -1397,6 +1397,7 @@ unittest-depends = \
|
|||||||
|
|
||||||
ifeq ($(continuations),true)
|
ifeq ($(continuations),true)
|
||||||
continuation-tests = \
|
continuation-tests = \
|
||||||
|
extra.ComposableContinuations \
|
||||||
extra.Continuations \
|
extra.Continuations \
|
||||||
extra.Coroutines \
|
extra.Coroutines \
|
||||||
extra.DynamicWind
|
extra.DynamicWind
|
||||||
|
43
test/extra/ComposableContinuations.java
Normal file
43
test/extra/ComposableContinuations.java
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
package extra;
|
||||||
|
|
||||||
|
import static avian.Continuations.shift;
|
||||||
|
import static avian.Continuations.reset;
|
||||||
|
|
||||||
|
import avian.FunctionReceiver;
|
||||||
|
import avian.Function;
|
||||||
|
|
||||||
|
import java.util.concurrent.Callable;
|
||||||
|
|
||||||
|
public class ComposableContinuations {
|
||||||
|
private static void expect(boolean v) {
|
||||||
|
if (! v) throw new RuntimeException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
expect(2 * reset(new Callable<Integer>() {
|
||||||
|
public Integer call() throws Exception {
|
||||||
|
return 1 + shift(new FunctionReceiver<Integer, Integer>() {
|
||||||
|
public Integer receive
|
||||||
|
(Function<Integer, Integer> continuation)
|
||||||
|
throws Exception
|
||||||
|
{
|
||||||
|
return continuation.call(5);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}) == 12);
|
||||||
|
|
||||||
|
expect(1 + reset(new Callable<Integer>() {
|
||||||
|
public Integer call() throws Exception {
|
||||||
|
return 2 * shift(new FunctionReceiver<Integer, Integer>() {
|
||||||
|
public Integer receive
|
||||||
|
(Function<Integer, Integer> continuation)
|
||||||
|
throws Exception
|
||||||
|
{
|
||||||
|
return continuation.call(continuation.call(4));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}) == 17);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user