3 ms·
Typeclasses are roughly equivalent to passing abstract factories around. This is enough to solve the expression problem and is known as Tagless final encoding,
by Tarean 6y ago
Typeclasses are roughly equivalent to passing abstract factories around. This is enough to solve the expression problem and is known as Tagless final encoding, or object algebras in oop:
interface Num<A> {
A add(A l, A r);
A lit(int i);
....
}
class PrintNum implements Num<String> {
String lit(int i){ return Integer.toString(i); }
String add(String l, String r) { return l + " + " + r;}
...
}
class NumInt implements Num<Int> {...}
function A foo<A>(Num<A> f) {
return f.add(f.lit(3), f.lit(4));
}
You can add new functions by extending the interface, you can add new implementations by implementing those interfaces.
However you need one class which implements all necessary interfaces for your final type to run the code. This means boilerplate if the interfaces come from different libraries.
You can reduce copying by using adapters which implement some interfaces and forward the rest - but then all adapters have to forward all unrelated methods! This is known as the quadratic instance problem in MTL.
There are lots of attempts to solve this in haskell and currently they are all worse then Tagless final on some axis, usually performance.