|
import static java.nio.charset.StandardCharsets.ISO_8859_1; |
|
import static java.nio.charset.StandardCharsets.UTF_8; |
|
|
|
import java.lang.reflect.Constructor; |
|
import java.lang.reflect.Executable; |
|
import java.lang.reflect.InvocationTargetException; |
|
import java.lang.reflect.Method; |
|
import java.nio.charset.Charset; |
|
import java.util.Arrays; |
|
import java.util.Collections; |
|
import java.util.Comparator; |
|
import java.util.List; |
|
import java.util.Random; |
|
import java.util.function.Function; |
|
|
|
public final class Currier3 { |
|
public static <T, R> Function<T, R> curry3(Method method) { |
|
return new FunctionE<>(method); |
|
} |
|
|
|
public static <T, R, K extends T> Function<T, R> curry3(Constructor<K> constructor) { |
|
return new FunctionE<>(constructor); |
|
} |
|
|
|
private static final class FunctionE<T, R> implements Function<T, R> { |
|
private static final Object[] EMPTY = new Object[0]; |
|
|
|
private final Executable executable; |
|
private final int parameterCount; |
|
private final T self; |
|
private final int invocationCount; |
|
private final Object[] env; |
|
|
|
public FunctionE(Method method) { |
|
this(method, null, 0, EMPTY); |
|
} |
|
|
|
public FunctionE(Constructor<? extends T> constructor) { |
|
this(constructor, null, 0, EMPTY); |
|
} |
|
|
|
private FunctionE( |
|
Executable executable, |
|
T self, |
|
int invocationCount, |
|
Object[] env) { |
|
this.executable = executable; |
|
this.parameterCount = executable.getParameterCount(); |
|
this.invocationCount = invocationCount; |
|
this.self = self; |
|
this.env = env; |
|
} |
|
|
|
@SuppressWarnings("unchecked") |
|
@Override |
|
public R apply(T t) { |
|
final T newSelf; |
|
final Object[] newEnv; |
|
|
|
if (invocationCount == 0) { |
|
newSelf = t; |
|
newEnv = env; |
|
} else { |
|
newSelf = self; |
|
newEnv = Arrays.copyOf(env, invocationCount); |
|
|
|
newEnv[invocationCount - 1] = t; |
|
} |
|
|
|
if (invocationCount == parameterCount) { |
|
return invoke(newSelf, newEnv); |
|
} |
|
|
|
return (R) new FunctionE<>( |
|
executable, |
|
newSelf, |
|
1 + invocationCount, |
|
newEnv); |
|
} |
|
|
|
@SuppressWarnings("unchecked") |
|
private final R invoke(T self, Object[] args) { |
|
try { |
|
if (executable instanceof Method) { |
|
Method m = (Method) executable; |
|
return (R) m.invoke(self, args); |
|
} else if (executable instanceof Constructor) { |
|
Constructor<R> c = (Constructor<R>) executable; |
|
return c.newInstance(args); |
|
} else { |
|
throw new IllegalStateException("Cannot handle type " + executable.getClass()); |
|
} |
|
} catch (IllegalAccessException e) { |
|
throw new RuntimeException(e); |
|
} catch (InstantiationException | InvocationTargetException e) { |
|
throw new RuntimeException(e.getCause()); |
|
} |
|
} |
|
} |
|
|
|
public static void main(String[] args) throws Exception { |
|
/* |
|
* instance method |
|
*/ |
|
Method listGet = List.class.getMethod("get", int.class); |
|
Function<List<?>, |
|
Function<Integer, String>> c3 = curry3(listGet); |
|
List<String> list = Arrays.asList("zero", "one", "two"); |
|
|
|
String two = c3 |
|
.apply(list) |
|
.apply(2); |
|
System.out.println(two); // prints two |
|
|
|
/* |
|
* static method |
|
*/ |
|
Method binarySearch = Collections.class.getMethod("binarySearch", |
|
List.class, Object.class, Comparator.class); |
|
Function<Void, |
|
Function<List<? extends String>, |
|
Function<String, |
|
Function<Comparator<? super String>, Integer>>>> c3static = curry3(binarySearch); |
|
Integer index = c3static |
|
.apply(null) // static method, no instance |
|
.apply(Arrays.asList("0;1;2;3;4;5;6;7".split(";"))) |
|
.apply("7") |
|
.apply((s1, s2) -> s1.compareTo(s2)); |
|
System.out.println(index); // prints 7 |
|
|
|
/* |
|
* No arg method |
|
*/ |
|
Method nextDouble = Random.class.getMethod("nextDouble"); |
|
Function<Random, Double> randomInvoke = curry3(nextDouble); |
|
Random random = new Random(1753592585); |
|
double randomDouble = randomInvoke.apply(random).doubleValue(); |
|
System.out.println(10 * randomDouble); // prints 3.1415926547261828 |
|
|
|
/* |
|
* constructor |
|
*/ |
|
Constructor<String> stringConstructor = String.class.getConstructor(byte[].class, Charset.class); |
|
Function<String, |
|
Function<byte[], |
|
Function<Charset, String>>> c3cons = curry3(stringConstructor); |
|
String byteArray = c3cons |
|
.apply(null) |
|
.apply("ââªâ¡âÒ¯".getBytes(ISO_8859_1)) |
|
.apply(UTF_8); |
|
System.out.println(byteArray); // prints ⊂∪ⓡ╓ү |
|
} |
|
} |