Collect arguments to apply to curried functions in Java/Scala - java

I would like to create a class in Java 8 which is able to recursively create an object which has a method that takes a function parameter based on the parameters I added.
For example, I would like to be able to do this:
new X().param(23).param("some String").param(someObject)
.apply((Integer a) -> (String b) -> (Object c) -> f(a,b,c))
The apply method would then apply the collected parameters to the given function.
I feel this should be possible without reflection while maintaing type-safety, but I can't quite figure out how. A solution in Scala is also welcome, if I can translate it to Java 8. If it's not possible, I'll also accept an answer that explains why.
What I have so far is essentially this:
class ParamCmd<A,X> {
final A param;
public ParamCmd(A param) {
this.param = param;
}
public<B> ParamCmd<B, Function<A,X>> param(B b) {
return new ParamCmd<>(b);
}
public void apply(Function<A,X> f) {
// this part is unclear to me
}
public static void main(String[] args) {
new ParamCmd<Integer,String>(0).param("oops").param(new Object())
// the constructed function parameters are reversed relative to declaration
.apply((Object c) -> (String b) -> (Integer a) ->
"args were " + a + " " + b + " " + c
);
}
}
As noted in the code comments, my problems are keeping the function parameters in the order of the calls of param(), and actually applying the parameters.

For an unlimited amount of parameters, the only solution I could think of is with Heterogeneous Lists in Scala.
It is probably isn't feasible in Java as there is type level computation going on with path-dependant types.
Using Heterogeneous Lists and Path-Dependant types:
import scala.language.higherKinds
object Main extends App {
val builder1 = HCons(23, HCons("Hello", HNil))
val builder2 = HCons(42L, builder1)
val res1:String = builder1.apply(i => s => i + s)
val res2:String = builder2.apply(l => i => s => (i+l) + s)
println(res1) // 23Hello
println(res2) // 65Hello
}
sealed trait HList {
type F[Res]
def apply[Res]: F[Res] => Res
}
case class HCons[Head, HTail <: HList](head: Head, tail: HTail) extends HList {
type F[Res] = Head => (tail.type)#F[Res]
def apply[Res]: F[Res] => Res = f => tail.apply(f(head))
}
case object HNil extends HList {
type F[Res] = Res
def apply[Res]: F[Res] => Res = identity
}
This code prints:
23Hello
65Hello
The second, more limited way of doing this, but which might work with Java, is to create multiple classes for each function length, which returns the next sized function length class wrapping the value, up to some maximal length - See the Applicative Builder in Scalaz: "Scalaz Applicative Builder"

This doesn't answer your question. However, maybe it helps someone to find a solution, or to explain why it isn't possible in Java and/or Scala.
It can be done in C++, with an arbitrary number of parameters, and without losing type-safety. The call-side look as follows. Unfortunately, the lambda syntax in C++ is quite verbose.
bar{}.param(23).param("some String").param(4.2).apply(
[](int i) {
return [=](std::string s) {
return [=](double d) {
std::cout << i << ' ' << s << ' ' << d << '\n';
};
};
});
Following is the definition of foo and bar. The implementation is straight-forward. However, I doubt that it is possible to build something like this in Java, because the way type parameters work in Java. Generics in Java can only be used to avoid type casts, and that's not enough for this use case.
template <typename Param, typename Tail>
struct foo {
Param _param;
Tail _tail;
template <typename P>
auto param(P p) {
return foo<P, foo>{p, *this};
}
template <typename Function>
auto apply(Function function) {
return _tail.apply(function)(_param);
}
};
struct bar {
template <typename P>
auto param(P p) {
return foo<P, bar>{p, *this};
}
template <typename Function>
auto apply(Function function) {
return function;
}
};

Sorry I just could give some leads in Scala:
Perhaps it would help to have a look at http://www.scala-lang.org/api/2.10.4/index.html#scala.Function$
.apply((Integer a) -> (String b) -> (Object c) -> f(a,b,c))
pretty much looks like Function.uncurried
param(23).param("some String").param(someObject)
could be implemented using a list for an accumulator if you don't care for Type safety. If you want to keep the Types you could use the HList out of Shapeless https://github.com/milessabin/shapeless which comes with a handy tuppled method.
Implementation of param():
import shapeless._
import HList._
import syntax.std.traversable._
class Method(val l : HList = HNil) {
def param(p: Any) = new Method( p :: l )
}
Example
scala> val m = new Method().param(1).param("test")
m: Method = Method#1130ad00
scala> m.l
res8: shapeless.HList = test :: 1 :: HNil

Related

Returning typed collection from Scala 2.13 method to Java 8 caller

I want to return java.util.List<Integer>s to the Java 8 code below instead of the java.util.List<Object>s that are returned from the following Scala 2.13.0 code. Both the Java and the Scala code could be modified to suit. I don't want to force any type conversions, for example no (java.util.List<Integer>) or .asInstanceOf[java.util.List[Int]] casts.
collections.FunctionConverterFromJava.scala
trait FunctionConverterFromScala {
import java.util.{List => JList}
import scala.collection._
val intoEvenOdd: JList[Int] => (JList[Int], JList[Int]) = {
import scala.jdk.CollectionConverters._
javaList: JList[Int] =>
javaList.asScala.partition(_ % 2 == 0) match {
case (even: mutable.Buffer[Int], odd: mutable.Buffer[Int]) =>
(even.asJava, odd.asJava)
}
}
}
object FunctionConverterFromJava extends FunctionConverterFromScala {
import java.util.{function, List => JList}
def reverse(string: String): String = string.reverse
def zipChars(string: String): IndexedSeq[(Char, Int)] = string.zipWithIndex
val intoEvenOddForJava: function.Function[JList[Int], (JList[Int], JList[Int])] = {
import scala.jdk.FunctionConverters._
intoEvenOdd.asJava
}
}
object FunctionConverterFun extends App with FunctionConverterFromScala {
val jList: java.util.List[Int] = {
import scala.jdk.CollectionConverters._
(1 to 10).asJava
}
println(intoEvenOdd(jList))
}
Java program
import collections.FunctionConverterFromJava$;
import scala.Tuple2;
import scala.collection.immutable.IndexedSeq;
import java.util.Arrays;
import java.util.List;
public class FunctionConverterFun {
public static void main(String[] args) {
String string = "Hello!";
String reversed = FunctionConverterFromJava$.MODULE$.reverse(string);
System.out.println("reversed = " + reversed);
IndexedSeq<Tuple2<Object, Object>> zippedChars = FunctionConverterFromJava$.MODULE$.zipChars(string);
System.out.println("zippedChars = " + zippedChars);
List<Object> list1 = Arrays.asList(1, 2);
Tuple2<List<Object>, List<Object>> list2 = FunctionConverterFromJava$.MODULE$.intoEvenOddForJava().apply(list1);
System.out.println("list2 = " + list2);
java.util.function.Function<List<Object>, Tuple2<List<Object>, List<Object>>> f = FunctionConverterFromJava$.MODULE$.intoEvenOddForJava();
Tuple2<List<Object>, List<Object>> list3 = f.apply(list1);
System.out.println("list3 = " + list3);
}
}
The issue is type erasure turns java.util.List[scala.Int] into java.util.List<java.lang.Object>. For example, javap output for intoEvenOddForJava is
public scala.Function1<java.util.List<java.lang.Object>, scala.Tuple2<java.util.List<java.lang.Object>, java.util.List<java.lang.Object>>> intoEvenOddForJava();
However, if we were to change from scala.Int to java.lang.Integer like so
object FunctionConverterFromJava extends FunctionConverterFromScala {
...
val intoEvenOddForJava: function.Function[JList[java.lang.Integer], (JList[java.lang.Integer], JList[java.lang.Integer])] = {
intoEvenOdd.asJava.asInstanceOf[function.Function[JList[java.lang.Integer], (JList[java.lang.Integer], JList[java.lang.Integer])]]
}
}
then we avoid type erasure according to javap output
public java.util.function.Function<java.util.List<java.lang.Integer>, scala.Tuple2<java.util.List<java.lang.Integer>, java.util.List<java.lang.Integer>>> intoEvenOddForJava();
Now from Java we can call as required
java.util.function.Function<List<Integer>, Tuple2<List<Integer>, List<Integer>>> f = FunctionConverterFromJava$.MODULE$.intoEvenOddForJava();
Tuple2<List<Integer>, List<Integer>> list3 = f.apply(list1);
System.out.println("list3 = " + list3);
which outputs
list3 = ([2],[1])
Now I understand that you wish to avoid asInstanceOf, however notice it would be hidden in the library FunctionConverterFromJava, that is, call-site would be clear of asInstanceOf. If you still wish to avoid asInstanceOf completely, then consider adding the following to FunctionConverterFromScala
val intoEvenOddAsJava: JList[java.lang.Integer] => (JList[java.lang.Integer], JList[java.lang.Integer]) = {
import scala.jdk.CollectionConverters._
javaList: JList[java.lang.Integer] =>
javaList.asScala.partition(_ % 2 == 0) match {
case (even: mutable.Buffer[java.lang.Integer], odd: mutable.Buffer[java.lang.Integer]) =>
(even.asJava, odd.asJava)
}
}
and then call intoEvenOddAsJava.asJava in FunctionConverterFromJava.intoEvenOddForJava.
That asInstanceOf hidden in library might be acceptable because
...the underlying representation of Int is Integer you can cast
directly to java.util.List[java.lang.Integer]
Addressing the comment, Eugene's answer explains
...how does it know
about Integer (via that checkcast) if generics are erased? The answer
is the optional Signature that is generated when A is compiled, or in
your cases:
()Lscala/collection/immutable/List<Ljava/lang/Object;>; //fooInt
()Lscala/collection/immutable/List<Ljava/lang/Integer;>; // fooInteger
This Signature information is what is used by the compiler to enforce
type safety at callsites, via runtime checks; if this field would not
be present - that would have been impossible.

Scala accept only String or Int generic case class in List

I have a case class defined as below
case class ChooseBoxData[T](index:T, text:String)
Is it possible to declare a List so that the list only accept type of ChooseBoxData[String] and ChooseBoxData[Int]?
What I expected is something like:
val specialList:List[some type declaration] = List(
ChooseBoxData[String]("some string","some string"),/* allow, because is ChooseBoxData[String]*/
ChooseBoxData[Int](12,"some string"), /* also allow, because is ChooseBoxData[Int]*/
ChooseBoxData[Boolean](true,"some string")/* not allow type other than ChooseBoxData[String] or ChooseBoxData[Int]*/
)
Something like this maybe:
trait AllowableBoxData
object AllowableBoxData {
private of[T](cbd: ChooseBoxData[T]) = new ChooseBoxData(cbd.index, cbd.text)
with AllowableBoxData
implicit def ofInt(cbd: ChooseBoxData[Int]) = of(cbd)
implicit def ofString(cbd: ChooseBoxData[String]) = of(cbd)
}
Now you can do things like
val list: List[ChooseBoxData[_] with AllowableBoxData] = List(ChooseBoxData("foo", "bar"), ChooseBoxData(0, "baz")
But not val list: List[AllowableBoxData] = List(ChooseBoxData(false, "baz"))
Also, if you were looking to declare a function argument rather than just a variable, there would be a bit more elegant solution:
trait CanUse[T]
implicit case object CanUseInt extends CanUse[Int]
implicit case object CanUseString extends CanUse[String]
def foo[T : CanUse](bar: List[ChooseBoxData[T]])
Here's what I came up with:
First, we create the following Algebraic Data Types (ADT):
sealed trait StringInt
case class Stringy(s : String) extends StringInt
case class Inty(s : Int) extends StringInt
And define ChoooseBoxData as follows:
case class ChooseBoxData(index : StringInt, text : String)
Then we define the following implicts to convert Int and String in the scope to the defined ADT:
object CBImplicits {
implicit def conv(u : String) = Stringy(u)
implicit def conv2(u : Int) = Inty(u)
}
Now, we can enforce the requirement in the question. Here is an example:
import CBImplicits._
val list = List(ChooseBoxData("str", "text"),
ChooseBoxData(1, "text"),
ChooseBoxData(true, "text"))
Trying to run the above, the compiler will complain about type mismatch. But this will compile and run:
List(
ChooseBoxData("str", "text"),
ChooseBoxData(1, "text"),
ChooseBoxData(12, "text2"))
which results in:
a: List[ChooseBoxData] =
List(ChooseBoxData(Stringy(str),text), ChooseBoxData(Inty(1),text), ChooseBoxData(Inty(12),text2))
This preserves index type information (wrapped in StringInt supertype of course) which later can be easily extracted using pattern matching for individual elements.
It is easy to remove the wrapper for all elements too, but it will result in the index type to become Any which is what we would expect because Any is the lowest common ancestor for both String and Int in Scala's class hierarchy.
EDIT: A Solution Using Shapeless
import shapeless._
import syntax.typeable._
case class ChooseBoxData[T](index : T, text : String)
val a = ChooseBoxData(1, "txt")
val b = ChooseBoxData("str", "txt")
val c = ChooseBoxData(true, "txt")
val list = List(a, b, c)
val `ChooseBoxData[Int]` = TypeCase[ChooseBoxData[Int]]
val `ChooseBoxData[String]` = TypeCase[ChooseBoxData[String]]
val res = list.map {
case `ChooseBoxData[Int]`(u) => u
case `ChooseBoxData[String]`(u) => u
case _ => None
}
//result
res: List[Product with Serializable] = List(ChooseBoxData(1,txt), ChooseBoxData(str,txt), None)
So it allows compilation, but will replace invalid instances with None (which then can be used to throw a runtime error if desired), or you can directly filter the instances you want using:
list.flatMap(x => x.cast[ChooseBoxData[Int]])
//results in:
List[ChooseBoxData[Int]] = List(ChooseBoxData(1,txt))
You can build extra constraint on top of your case class.
import language.implicitConversions
case class ChooseBoxData[T](index:T, text:String)
trait MySpecialConstraint[T] {
def get: ChooseBoxData[T]
}
implicit def liftWithMySpecialConstraintString(cbd: ChooseBoxData[String]) =
new MySpecialConstraint[String] {
def get = cbd
}
implicit def liftWithMySpecialConstraintInt(cbd: ChooseBoxData[Int]) =
new MySpecialConstraint[Int] {
def get = cbd
}
// Now we can just use this constraint for out list
val l1: List[MySpecialConstraint[_]] = List(ChooseBoxData("A1", "B1"), ChooseBoxData(2, "B2"))
Why can't you do it like this:
object solution extends App {
case class ChooseBoxData[T](index: T, text: String) extends GenericType[T]
trait GenericType[T] {
def getType(index: T, text: String): ChooseBoxData[T] = ChooseBoxData[T](index, text)
}
val specialList = List(
ChooseBoxData[String]("some string", "some string"),
ChooseBoxData[Int](12, "some string"),
ChooseBoxData[Boolean](true, "some string")
)
println(specialList)
}
//output: List(ChooseBoxData(some string,some string), ChooseBoxData(12,some string), ChooseBoxData(true,some string))

Pattern matching on POJOs in Scala?

I'm trying to update some of my old Scala code to new APIs.
In one of the libraries I use, a case class has been converted to a simple POJO for compatibility reasons.
I was wondering if it is still possible somehow to use pattern matching for the Java class.
Imagine I have a simple Java class like:
public class A {
private int i;
public A(int i) {
this.i = i;
}
public int getI() {
return i;
}
}
After compilation, I would like to use it in pattern matching somehow like:
class Main extends App {
val a = ...
a match {
case _ # A(i) =>
println(i);
}
}
For the code above, I obviously get an error: Main.scala:7: error: object A is not a case class constructor, nor does it have an unapply/unapplySeq method.
Is there any trick I could use here?
Thanks in advance!
It's a little late in the night here for subtlety, but
object `package` {
val A = AX
}
object AX {
def unapply(a: A): Option[Int] = Some(a.getI)
}
object Test extends App {
Console println {
new A(42) match {
case A(i) => i
}
}
}
Write unapply yourself:
object A {
def unapply(x: A) = Some(x.getI)
}
#som-snytt's answer is correct - but if you are doing this just for e.g. pattern-matching then I prefer the more succinct approach:
import spray.httpx.{UnsuccessfulResponseException => UrUnsuccessfulResponseException}
object UnsuccessfulResponseException {
def unapply(a: UrUnsuccessfulResponseException): Option[HttpResponse]
= Some(a.response)
}
... match {
case Failure(UnsuccessfulResponseException(r)) => r
case ...
}
Ur is a pretentious way of saying "original", but it only takes two letters.

Accept anonymous comparator in Scala?

How can I accept a function to pass to Vector.sortBy() in scala as an argument?
Currently I have a function like this:
private def buildTree(data: Vector[Data2D]): Node = {
var sorted: Vector[Data2D] = data.sortBy(_.x)
// etc...
}
However, I would like to pass either "_.x" (sort on x) or "_.y" as an argument to the function, so I can do something like this:
private def buildTree(data: Vector[Data2D], comparator): Node = {
var sorted: Vector[Data2D] = data.sortBy(comparator)
// etc...
if(comparator == _.x){
buildTree(data, _.y)
}
}
So I would like to check what the current "comparator" is, and then recurse passing it the comparator for the y coordinate.
I hope this is clear. In Java I would write it as:
private Node buildTree(List<Data2D> data, Comparator<Data2D> comparator) {
// Sorted on x or y
Collections.sort(data, comparator);
// ... snip ...
if (comparator instanceof XComparator) {
// Recurse
Node subtree = buildTree(data, YComparator.INSTANCE);
ret.setSubtree(subtree);
}
return ret;
}
// Then build tree is called like:
Node root = tree.buildTree(data, XComparator.INSTANCE)
Actually, you want an Ordering. Like this:
class XOrdering extends Ordering[Data2D] {
override def compare(x: Data2D, y: Data2D): Int = Ordering.Int(x.x, y.x)
}
class YOrdering extends Ordering[Data2D] {
override def comapre(x: Data2D, y: Data2D): Int = Ordering.Int(x.y, y.y)
}
private def buildTree(data: Vector[Data2D], ordering: Ordering[Data2D]): Node = {
var sorted: Vector[Data2D] = data.sorted(ordering)
// etc...
ordering match {
case _: XOrdering => buildTree(data, YOrdering)
case _: YOrdering => buildTree(data, XOrdering)
case _ => error("I don't know what that ordering is!")
}
}
The sortBy method just creates an Ordering for you. sortBy(_.x) is equivalent to sorted(Ordering.by(_.x)).
If you check the docs, you see that sortBy takes one argument: f: A => B. Looks like a generic function that takes A as an argument and produces a B. So, let's give that a try:
val orderX = (d: Data2D) => d.x
val orderY = (d: Data2D) => d.y
which defines the two functions that we want. Now we can call
data.sortBy(orderer)
and test
if (orderer==orderX) buildTree(data, orderY)
(though I would recommend passing in both comparators as arguments rather than searching for specific constants).

clojure/scala interop?

I am attempting to interop to this simple scala code, but am having some troubles.
package indicators
class DoubleRingBuffer(val capacity:Int=1000) {
var elements = new Array[Double](capacity);
private var head=capacity-1
private var max=0
def size ():Int = {
return max+1
}
def add(obj:Double):Double = {
head-=1
if (head<0) head=capacity-1
return set(max+1,obj)
}
def set(i:Int,obj:Double):Double = {
System.out.println("HI")
if (i>=capacity || i<0)
throw new IndexOutOfBoundsException(i+" out of bounds")
if (i>=max) max=i
var index = (head+i)%capacity
var prev = elements(index)
elements(index)=obj
return prev
}
def get(i:Int=0):Double = {
System.out.println("size is "+size())
if (i>=size() || i<0)
throw new IndexOutOfBoundsException(i+" out of bounds")
var index = (head+i)%capacity
return elements(index)
}
}
In clojure, i do this
(import 'indicators.DoubleRingBuffer)
(def b (DoubleRingBuffer. 100))
(pr (.size b)) ;;ERROR: No matching field found: size for class indicators.DoubleRingBuffer
(pr (.get b 33)) ;;returns 0: should throw an index out of bounds error!
(pr (.get b 100)) ;;throws index out of bounds error, as it should
In addition, i do not get any output to the console! Testing this code using scala works as expected. Whats going on here and how can i fix it so that clojure can use the scala code?
Try these in REPL:
(class b) will probably tell you it's indicators.DoubleRingBuffer.
(vec (.getDeclaredMethods (class b))) will give you a vector of all methods declared in your class as if it was a Java class, so you can see their signatures.
Now, call your methods as seen in the signatures, with these method names and parameters.
I have a feeling the problem is in Scala's dealing with default value for method parameter.
EDIT: As OP described in a comment, it isn't.
If that doesn't work you can try to decompile your Scala bytecode to Java to find out how does DoubleRingBuffer class look like.

Categories