Skip to content

Instantly share code, notes, and snippets.

@xsc
Created March 22, 2020 17:28
Show Gist options
  • Save xsc/20786a4f8cb9dc3f4ac06fe1cde55665 to your computer and use it in GitHub Desktop.
Save xsc/20786a4f8cb9dc3f4ac06fe1cde55665 to your computer and use it in GitHub Desktop.
Haxlike (Java)
package yannick.haxl;
import java.util.List;
import java.util.stream.Collectors;
import lombok.Value;
@Value
public class ListNode<T> implements Node<List<T>> {
List<Node<T>> elements;
@Override
public List<Resolvable<?, ?>> allResolvables() {
return elements
.stream()
.flatMap(node -> node.allResolvables().stream())
.collect(Collectors.toList());
}
@Override
public <V, R extends Resolvable<V, R>> Node<List<T>> injectValue(
R resolvable,
V value
) {
final List<Node<T>> injected = elements
.stream()
.map(node -> node.injectValue(resolvable, value))
.collect(Collectors.toList());
if (injected.stream().allMatch(Node::hasValue)) {
return new ValueNode<>(
injected
.stream()
.map(Node::getValue)
.collect(Collectors.toList())
);
}
return new ListNode<>(injected);
}
@SafeVarargs
@SuppressWarnings("varargs")
public static <T> ListNode<T> of(Node<T>... elements) {
return new ListNode<>(List.of(elements));
}
}
package yannick.haxl;
import java.util.List;
import java.util.stream.Collectors;
import lombok.Value;
public class Main {
public static void main(String[] args) {
Node<?> n = ListNode
.of(new TestResolvable(14).map(v -> v + 2), new TestResolvable(14))
.map(
x -> {
System.out.println("list is:" + x);
return x.size();
}
);
System.out.println(n);
System.out.println("resolving");
System.out.println(resolve(n));
}
public static <T> T resolve(Node<T> node) {
Node<T> n = node;
while (!n.hasValue()) {
n = resolveNext(n);
}
return n.getValue();
}
private static <T, V, R extends Resolvable<V, R>> Node<T> resolveNext(
Node<T> node
) {
final List<R> batch = selectBatch(node);
final List<V> results = batch.get(0).resolveAll(batch);
Node<T> n = node;
for (int i = 0; i < results.size(); i++) {
n = n.injectValue(batch.get(i), results.get(i));
}
return n;
}
@SuppressWarnings("unchecked")
private static <T, V, R extends Resolvable<V, R>> List<R> selectBatch(
Node<T> n
) {
final List<Resolvable<?, ?>> resolvables = n.allResolvables();
final Class<R> cls = (Class<R>) resolvables.get(0).getClass();
return resolvables
.stream()
.filter(r -> r.getClass().equals(cls))
.map(cls::cast)
.distinct()
.collect(Collectors.toList());
}
@Value
private static class TestResolvable
implements Resolvable<Integer, TestResolvable> {
Integer value;
@Override
public List<Integer> resolveAll(List<TestResolvable> batch) {
System.out.printf("resolving %d TestResolvables%n", batch.size());
return batch
.stream()
.map(TestResolvable::getValue)
.collect(Collectors.toList());
}
}
}
package yannick.haxl;
import java.util.function.Function;
import java.util.List;
import lombok.Value;
@Value
public class MapNode<T, R> implements Node<R> {
Node<T> inner;
Function<T, R> f;
@Override
public List<Resolvable<?, ?>> allResolvables() {
return inner.allResolvables();
}
@Override
public <V, I extends Resolvable<V, I>> Node<R> injectValue(
I resolvable,
V value
) {
return new MapNode<>(inner.injectValue(resolvable, value), f);
}
@Override
public boolean hasValue() {
return inner.hasValue();
}
@Override
public R getValue() {
return f.apply(inner.getValue());
}
}
package yannick.haxl;
import java.util.function.Function;
import java.util.List;
public interface Node<T> {
@SuppressWarnings("squid:S1452")
List<Resolvable<?, ?>> allResolvables();
<V, R extends Resolvable<V, R>> Node<T> injectValue(R resolvable, V value);
default boolean hasValue() {
return false;
}
default T getValue() {
throw new IllegalStateException("This node does not have a value.");
}
default <R> Node<R> map(Function<T, R> f) {
return new MapNode<>(this, f);
}
}
package yannick.haxl;
import java.util.List;
public interface Resolvable<T, R extends Resolvable<T, R>> extends Node<T> {
List<T> resolveAll(List<R> batch);
@Override
default List<Resolvable<?, ?>> allResolvables() {
return List.of(this);
}
@Override
@SuppressWarnings("unchecked")
default <V, I extends Resolvable<V, I>> Node<T> injectValue(
I resolvable,
V value
) {
if (this.equals(resolvable)) {
return new ValueNode<>((T) value);
}
return this;
}
}
package yannick.haxl;
import java.util.List;
import lombok.Value;
@Value
public class ValueNode<T> implements Node<T> {
T value;
@Override
public List<Resolvable<?, ?>> allResolvables() {
return List.of();
}
@Override
public boolean hasValue() {
return true;
}
@Override
public <V, R extends Resolvable<V, R>> Node<T> injectValue(
R resolvable,
V value
) {
return this;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment