This is exactly what I was looking for! I'll give it a try and then see about integrating something like this into jss. Thanks so much, Alan
On Tue, Aug 23, 2022 at 11:10 PM 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