Is there any way to express f-bound types in java where at the call site, a generic response is returned?
interface Functor<T extends Functor<T>>
public <B> T<B> map(Function<A, B> fn); // won't compile because types don't match
I can use f-bound types if the type never changes, but in the case of map, I need a new type. Is there a way to express this in java?
What I am really looking for is any way that I can get something like higher kinds even though I know javac doesn't support higher kinded types.
Lets say we have a List<A>
and want this interface to return a List<B>
. But don't want this interface to know anything about List
.
Reading the Wikipedia definition of functor, it sounds like you want to define a generic type which is able to map from one category (Java type) to another. In your example above, to map from a List<A>
to List<B>
where the types A
and B
are generic.
If this is your aim, then consider the following interface for the definition of a Functor
type:
public interface Functor<CategoryA, CategoryB> {
public CategoryB map(CategoryA instance);
}
This declares that the Functor
type deals in two generic parameter types, CategoryA
and CategoryB
and no constraints are put on these parameter types. It also declares that a method map
must be implemented which maps from an object of type CategoryA
to an object of type CategoryB
.
Suppose, based on your example, you now want to create a concrete instance of a Functor
which maps from List<Integer>
to List<String>
. You might create the following class:
public class IntegerListToStringList implements Functor<List<Integer>, List<String>> {
@Override
public List<String> map(List<Integer> integerList) {
List<String> stringList = new ArrayList<>(integerList.size());
for(Integer intValue : integerList) {
stringList.add(Integer.toString(intValue));
}
return stringList;
}
}
You could then invoke this concrete Functor
implementation like so:
Functor<List<Integer>, List<String>> functor = new IntegerListToStringList();
Integer[] intArray = new Integer[] {2, 3, 5, 7, 11, 13};
List<Integer> intList = Arrays.asList(intArray);
List<String> stringList = functor.map(intList);
System.out.println("String list: " + stringList);
Now any method which is expecting a parameter of type Functor<List<Integer>, List<String>>
can accept an instance of type IntegerListToStringList
.