Created
October 8, 2023 20:25
-
-
Save stefanofago73/f16397426f4d31e262e9742a36478dc7 to your computer and use it in GitHub Desktop.
Are possible Haskell Typeclasses in Java?
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// Empty Typeclass | |
// | |
interface Empty<A> { | |
A empty(); | |
static Empty<Integer> emptyInt() { | |
return () -> 0; | |
} | |
static Empty<String> emptyString() { | |
return () -> ""; | |
} | |
} | |
// | |
// Show Typeclass | |
// | |
public interface Show<A> { | |
String show(A a); | |
static Show<Stringable> stringableShow() { | |
return a -> "[stringable]"+a.toString(); | |
} | |
static Show<Object> objectShow() { | |
return a -> "[base]"+String.valueOf(a); | |
} | |
static Show<Integer> integerShow() { | |
return a -> "[number]"+String.valueOf(a); | |
} | |
} | |
// | |
// Monoid Typeclass | |
// | |
public interface Monoid<A> extends Empty<A> { | |
A combine(A x, A y); | |
static Monoid<Integer> intMonoid() | |
{ | |
return new Monoid<Integer>() { | |
@Override | |
public Integer empty() { | |
return emptyInt().empty(); | |
} | |
@Override | |
public Integer combine(Integer x, Integer y) { | |
return x+y; | |
} | |
}; | |
} | |
static Monoid<String> stringMonoid() | |
{ | |
return new Monoid<String>() { | |
@Override | |
public String empty() { | |
return emptyString().empty(); | |
} | |
@Override | |
public String combine(String x, String y) { | |
return x+y; | |
} | |
}; | |
} | |
static Monoid<String> csvMonoid() | |
{ | |
return new Monoid<String>() { | |
@Override | |
public String empty() { | |
return emptyString().empty(); | |
} | |
@Override | |
public String combine(String x, String y) { | |
return x+";;"+y; | |
} | |
}; | |
} | |
} | |
// | |
// Commodity Interface | |
// | |
public interface Stringable { | |
String toString(); | |
} | |
// | |
// Entry-Point to apply Typeclass to related Instances | |
// | |
public interface Operations { | |
static <A> String show(A instance, Show<A> typeclass) { | |
return typeclass.show(instance); | |
} | |
static <T> T combineAll(List<T> list, Monoid<T> monoid) { | |
return list.stream().reduce(monoid.empty(), monoid::combine); | |
} | |
} | |
// | |
// Examples: The composition is possible as "functions" | |
// that are defined by Operations Interface | |
// Can we find another way of composition... | |
// Theoretically a monadic approach is possible | |
// but it needs to be verified... | |
// | |
public class Usage implements Operations { | |
static class TestBean implements Stringable { | |
} | |
static List<Integer> intList() { | |
var intList = new ArrayList<Integer>(); | |
intList.add(8); | |
intList.add(10); | |
intList.add(5); | |
return intList; | |
} | |
static List<String> csvList() { | |
var csvList = new ArrayList<String>(); | |
csvList.add("pippo"); | |
csvList.add("pluto"); | |
csvList.add("paperino"); | |
return csvList; | |
} | |
static Consumer<String> console() | |
{ return System.out::println; } | |
public static void main(String[] args) { | |
var testBean = new TestBean(); | |
Consumer<String> console = console(); | |
// | |
// Using Show Type Class | |
// | |
console.accept(show(testBean, objectShow())); | |
console.accept(show(testBean, stringableShow())); | |
console.accept(show(testBean, TestBean::toString)); | |
// | |
// Using Monoid Type Class | |
// | |
console.accept("result: " + combineAll(new ArrayList<>(), intMonoid())); | |
console.accept("result: " + combineAll(intList(), intMonoid())); | |
console.accept("result: " + combineAll(csvList(), csvMonoid())); | |
// | |
// A complex composition | |
// | |
console.accept(show(combineAll(intList(), intMonoid()), integerShow())); | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment