3 ms·
This is somewhat glossing over the fact that you can only do this mechanical translation if you have access to the whole program, and the two approaches have dr
by deredede 3y ago
This is somewhat glossing over the fact that you can only do this mechanical translation if you have access to the whole program, and the two approaches have drastically different implications for modularity.
With the "data"/sum types approach, new analyses or transformations on the program can be added in another module, but new nodes can't be.
With the "codata"/protocol approach, new analyses can't be added (you are limited to those encoded in the protocol), but new nodes can easily be added in a separate module where you implement the protocol for them.
- valenterry 3y agoWhat you are refering to is known as the expression problem. > With the "data"/sum types approach, new analyses or transformations on the program can be added in another module, but new nodes can't be. That's not true at all. Typeclasses solve this exact problem very elegantly in (P)FP languages. In other languages there are sometimes similar solutions (such as object algebras[1] in Java) but it is more tricky and usually less orgonomic or impossible to do while keeping things typesafe. [1] https://www.cs.utexas.edu/~wcook/Drafts/2012/ecoop2012.pdf https://www.cs.utexas.edu/~wcook/Drafts/2012/ecoop2012.pdf
- 3cats-in-a-coat 3y agoTypeclasses dispatch is static. You can use a typeclass implementation as a proxy for holding a dynamically injected implementation you call through the typeclass implementation, but that's a hack, not exactly "elegant".
- valenterry 3y agoI don't think that matters in this case. The list of node-types is static in the context of the execution of the program so there is no need for nodes of the same types to have different behaviour, apart from the data/configuration that they store. The point in question was what happens if new node-types come in (e.g. through a plugin that extends the language). But in this case the number of node-types is still static and the new functionality can therefore be adapted using type-classes.
- 3cats-in-a-coat 3y agoThe assumption it's a closed system that received no new content at runtime is a very functional programming-like assumption, but quite restrictive in most real long-lived systems.
- valenterry 3y agoThat's not the assumption. The assumption is that the system does not receive new node-types at runtime. Think of the JVM: you can load new bytecode (e.g. classes) at runtime, but you can't load bytecode that contains features of newer jvm versions that isn't compatible with the existing one. I don't think this is a "functional programming-like assumption".
- deredede 3y agoCan you elaborate on what you mean by "typeclass dispatch is static"? I believe typeclasse in Haskell at least are lowered to an array of method, i.e. a vtable, and (single) dispatch happens at runtime.
- whateveracct 3y agoYep they desugar to dictionary-passing (vtable)..buuuut GHC is a helluva optimizing compiler and will often effectively make them static.
- deredede 3y agoI mean, sure, you can optimize a lot of the common cases (C++ compilers do the same), but that doesn't make the dispatch static, semantically.
- whateveracct 3y agoIt's static dispatch when it's monomorphic, I'd say.
- deredede 3y agoYes, the name slipped from my mind, thank you for pointing that out! With type classes however you mostly switch to the codata/protocol view, you can't pattern match on "the things that implement the type class" anymore and you have to rely on the methods provided by the type class.