mirror of
https://github.com/corda/corda.git
synced 2025-01-01 02:36:44 +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 {
|
||||
private Continuations() { }
|
||||
|
||||
private static final ThreadLocal<Reset> latestReset = new ThreadLocal();
|
||||
|
||||
/**
|
||||
* Captures the current continuation, passing a reference to the
|
||||
* 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,
|
||||
Callable thunk,
|
||||
Runnable after)
|
||||
@ -235,4 +307,13 @@ public class Continuations {
|
||||
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)
|
||||
continuation-tests = \
|
||||
extra.ComposableContinuations \
|
||||
extra.Continuations \
|
||||
extra.Coroutines \
|
||||
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