Skip to content

Instantly share code, notes, and snippets.

@stefanofago73
Created October 8, 2023 20:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save stefanofago73/f16397426f4d31e262e9742a36478dc7 to your computer and use it in GitHub Desktop.
Save stefanofago73/f16397426f4d31e262e9742a36478dc7 to your computer and use it in GitHub Desktop.
Are possible Haskell Typeclasses in Java?
//
// 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