4 ms·
I would be interested to hear how this interacts with typeclasses/traits. In seems like they maybe give you more flexibility to separate the requirement to hav
by jeremysalwen 6y ago
I would be interested to hear how this interacts with typeclasses/traits. In seems like they maybe give you more flexibility to separate the requirement to have an area from the requirement to have a perimeter. But I think you still run into the problem of having to "update your code" everywhere, just in a different way.
- dllthomas 6y agoPhillip Wadler coined the term (while recognizing that the concern was preexisting), and co-invented typeclasses specifically as an attempt to address it. So you're definitely right to think they're related.
- Kednicma 6y agoThe current situation is that it's like Karnaugh maps: If there are overlapping clauses and default/generic implementations, then yes, typeclasses/traits/interfaces can cut down on the amount of code needed. However, in the worst case, all of the implementations need to be provided.
- fanf2 6y agoThis is a pretty good article that I think will answer your question: https://eli.thegreenplace.net/2018/more-thoughts-on-the-expression-problem-in-haskell/ https://eli.thegreenplace.net/2018/more-thoughts-on-the-expr... - it shows how typeclasses almost but not quite solve the Expression Problem, then goes on to use higher-kinded types for a more complete solution.
- Tarean 6y agoTypeclasses 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.