I stumbled upon a little problem today. Consider a little wrapper class:
class Event<T> {
T value;
Class<T> type;
// other fields, getters and setters omitted for brevity
}
Now I was in a situation where I wanted to convert a Event<Long>
into a Event<String>
while preserving the other fields and updating the type
member.
Eventually I ended up with the most simple "solution":
Event<String> new = new Event(old.getValue().toString(), String.class, other, fields);
Having worked with Haskell on my pet projects however, I naturally longed for a function like fmap :: Functor f => (a -> b) -> f a -> f b
(read: given a function from a to b and a functor containing something of type a give me a result containing the b) and after finding no standard implementation I set out to write one myself:
interface Functor<T> {
Functor<S> fmap( Func1<T,S> f );
}
// ... in Event<T>:
Functor<S> fmap( Func1<T,S> f ) {
S newValue = f.call(this.value);
return new Event( newValue, newValue.getClass(), other, fields);
}
Now there is a problem with this solution: after the call to fmap in Java I am left with an instance of type Functor<String>
while the same function in Haskell would return a Event<String>
.
Is there a way to get my Event
back (without unsafely casting it)?
No, it isn't possible. For this to happen we would need to abstract over the Functor
in your interface, something like
interface Functor<T> as F<T> {
F<S> map(f : Function<T, S>);
}
But Java doesn't allow you to abstract over type constructors, just types. This is called Higher Kinded Types (HKT). Only a few (non-dependent) languages have HKTs, Scala and Haskell are the only two I can think of.
In fact HKTs are necessary to express a lot of abstractions,
category-extras
All of these involve abstracting over type constructors, not just concrete types.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With