Function is a convenient interface for cases when a more specific interface does not exist. But any Java interface with a single abstract method can be the target of a lambda expression:new Thread(() -> { System.out.println("foo"); }).run();The Thread constructor takes a Runnable argument, not a Function.Lambda is just syntax sugar for interfaces with a single method, so you can reproduce them on ABCL with the jinterface thing + some macrology.On Wed, 24 Aug 2022 at 05:10, Vibhu Mohindra <vibhu.mohindra@gmail.com> wrote:On 23/08/2022 05:27, Alan Ruttenberg wrote:
> There's a library I want to use that takes a lambda as an argument.
> Anyone know how to construct one in ABCL?
I assume it's a Java library taking a Java Lambda that you want to call
from ABCL.
A Java Lambda is really an instance of one of the classes in
java.util.function. Which one depends on how many parameters it has and
whether it returns a value. Let's assume your library wants a Java
Lambda that has one parameter and returns a value. That's a
java.util.function.Function. Say it looks like this:
//Lib.java
public class Lib {
public static void f(java.util.function.Function f) {
System.out.println("You answered: " + f.apply(5));
}
}
such that it can be used from Java with a Java Lambda like this:
Lib.f((Object x) -> (Integer)x * (Integer)x);
=> You answered: 25
You'd like to give it a Lisp Lambda from ABCL as follows:
(jstatic "f" "Lib" #'(lambda (x) (* x x)))
but that's not allowed because although Java can implicitly convert from
a Java Lambda to a java.util.function.Function, it can't convert from a
Lisp Lambda to a java.util.function.Function.
A Lisp Lambda is really an org.armedbear.lisp.Function. So one solution
is to adapt that.
//Adaptor.java
import org.armedbear.lisp.*;
public class Adaptor implements java.util.function.Function {
private org.armedbear.lisp.Function lispFn;
public Adaptor(org.armedbear.lisp.Function lispFunction) {
this.lispFn = lispFunction;
}
public Object apply(Object input) {
return lispFn.execute(
JavaObject.getInstance(input, true)).javaInstance();
}
}
and use it from ABCL like this:
(jstatic "f" "Lib" (jnew "Adaptor" #'(lambda (x) (* x x))))
=> You answered: 25
=> NIL
----
Notes:
I'm on Java 10, ABCL-1.4.0 (which is old).
I did this to build and run, starting with the jar and two java files in
the current directory:
javac -classpath abcl-1.4.0.jar:. Adaptor.java Lib.java
java -classpath abcl-1.4.0.jar:. org.armedbear.lisp.Main
> (jstatic "f" "Lib" (jnew "Adaptor" #'(lambda (x) (* x x))))
You can probably create the Adaptor class from within ABCL if you don't
like that it's written in Java, but I don't remember how to. ABCL's
documentation might describe such bytecode generation somewhere.
Pointers:
Java: java.util.function.*
ABCL: In org.armedbear.lisp, LispObject, JavaObject, Function
--
Vibhu