You can't do it directly, but there is a standard idiom for doing something like that - define the interface like this:
interface Functor<A, R extends Functor<A, R>>
And then in the implementing class, bind R to the implementing class:
class Option<A> implements Functor<A, Option<A>>
However, this doesn't let you write an actual functor. Try to write the map method on it:
class Option<A> implements Functor<A, Option<A>> {
private final A value;
public Option(A value) { this.value = value; }
@Override
public <B> Option<A> map(Function<A, B> fn) {
// er, i want to return an Option<B>, not an Option<A>
}
}
The problem is that you don't want to return an instance of the type of the receiver, you want to return an instance of a similar type with a different type parameter (Option<B> rather than Option<A>).
You would be absolutely fine if your functions were functions from values of some type to other values of that type (eg functions from integers to integers), because then A = B and you can get away with this. But there's no way to extend this hack to let you return an Option<B> from map.
The closest you can get in Java is probably this:
interface Functor<A, R extends Functor<?, R>>
class Option<A> implements Functor<A, Option<?>> {
private final A value;
public Option(A value) { this.value = value; }
@Override
public <B> Option<?> map(Function<A, B> fn) {
return new Option<B>(value != null ? fn.apply(value) : null);
}
}
There, you leave the element type of the returned functor undefined, as a wildcard, which lets you slip an Option<B> out as a return value.
The problem with that is that it's useless. Given:
Option<String> x;
Function<String, Integer> fn;
Then mapping the function over the option gives you:
Option<?> y = x.map(fn);
An Option<?>. Which is no use to man or beast, because it's lost the type information.
What you really want to be able to write is:
class Option<A> implements Functor<A, Option<_>>
Where the underscore is borrowed from Scala to mean "nothing to see here, move along please", and leaves that reference to Option in its unbound form. And then have a way of binding it right in the definition of the map function. But that's higher-kinded types, and Java doesn't have that.
If you were absolutely desperate to do this in Java, like if terrorists burst in and put a gun to your head and told you to do it, you could restore the type information by pebble-dashing the functor with some simple reflection:
interface Functor<A, R extends Functor<?, R>> {
<B> R map(Function<A, B> fn);
<B> Functor<B, R> as(Class<B> b);
}
class Option<A> implements Functor<A, Option<?>> {
// other stuff as above
@Override
public <B> Option<B> as(Class<B> b) {
return new Option<B>(b.cast(value));
}
}
Which, given the above definitions of x and fn, lets you write:
Option<Integer> y = x.map(fn).as(Integer.class);
And even the same thing but typed as functors, to show you there's nothing up my sleeve:
Functor<String, Option<?>> fx = x;
Functor<Integer, Option<?>> fy = fx.map(fn).as(Integer.class);
And as a separate function which contains no mention of the concrete functor class anywhere (although it does still need a type token for the result functor's parameter):
private <A, B, F extends Functor<?, F>> Functor<B, F> applyAbstractly(Functor<A, F> fx, Function<A, B> fn, Class<B> b) {
return fx.map(fn).as(b);
}
But to be honest, all of this is a bit like trying to carve a fine wooden sculpture with a chainsaw. If you want to do this, don't use Java. If you want to use Java, don't do this.