I think it’s a shame that no other mainstream language has adopted the ML-style module system. It is so ridiculously powerful but also simple (for the most part). Functors are the primary mechanism I use to architect my code and it is a wonderful tool.
Not totally absent from other languages - at least as a pattern.
Just hasn’t been as important as doing a good job of typeclasses was for us and typeclasses are nicer to use 90% of the time anyway.
The good thing is, Edward Yang is working on Backpack, so we’ll have a module system sooner or later. :)
I would love to see some resources/examples/guidance on advanced functor use for code architecture.
It’s still in the works but my Raft implementation, called Scow, uses functors heavily to separate the algorithm from various backend needs, such as the transport and storage:
I then further functorized serialization from sending/receiving on a TCP socket:
Now dead, but my attempt at a Pastry implementation separated out the Pastry algorithm from business logic and transport:
If you have any questions or thoughts or want further explanation, I’m happy to provide more if possible.
Great, thanks! I’ll read these and see what I learn.
One more note:
To many people they may say “I can do this in Java or whatever with an interface and passing the instance of the interface into the constructor”.
One can get a similar effect by doing this. However, functors have an important distinction that might be hard for me to explain but I’ll try.
With the Java solution, the composition happens at runtime and, when looking at a piece of code, it’s difficult to know how that piece of code was composed. For example a service that was parameterized over a transport layer. Some psuedoish Java code might look like:
HTTPTransport t = new HTTPTransport();
Service s = new Service(t);
What if we have another one that uses a protobuf transport:
PBTransport t = new PBTransport();
Service s = new Service(t)
These two services are indistinguishable from one another. You can pass it into any method that expects a service.
With functors, all of this happens at compile time and creates a new module. The resulting modules are unique and distinguishable from each other.
module HTTPService = Service.Make(HTTPTransport)
let t = HTTPTransport.start () in
let s = HTTPService.start t in
The value here providing a compile-time mechanism for composing disjoint elements together into a single thing. In order to do operations on s there I need to call operations using the HTTPService module.
For most problems this is exactly what you want. Compile time composition is perfectly fine. There is no need to pay the cognitive price of a dispatch table. It also lets you separate the statically composed elements of your program from the dynamically composed ones which happen at runtime through dispatch tables.
Not sure if I have eloquently explained the value of functors. I’m still in search of an adequate explanation.
The thing that always drove that home for me is the applicative versus generative divide.
Generative feels a lot more like the dynamic dispatch trick you’re doing in Java (though it’s not), but applicative drives home the idea that the generated modules are unique and specific to the syntactic form used to construct them (for better and worse).
This is a pretty cool talk if you want some perspective from the other side of things.
Scala seems to be quite close to ML-style modules, but it differs in some details.
It’s certainly nice to see that at least few languages care about a great module system (unlike e. g. Haskell) and working typeclasses (unlike e. g. Haskell).
I’m excited about Haskell’s backpack, because modules implies fixing typeclasses, but I’m also concerned because modules implies fixing typeclasses, and there will be a lot of ideological resistance against it.
I’m missing what you see as the similarity with Scala. Can you go into that a bit?
Object ≅ Structure
Class ≅ Functor
Trait ≅ Signature
Abstract Type ≅ Abstract Type
Refinement ≅ Sharing Constraint
Article about it: http://io.pellucid.com/blog/scalas-modular-roots
StackOverflow post on some of the differences: http://stackoverflow.com/questions/23006951/encoding-standard-ml-modules-in-oo
Talk which looks at it from a slightly different point of view: http://www.infoq.com/presentations/post-functional-scala-clojure-haskell
I hope this helps a bit!
Re modular roots:
I would say you have to squint really really hard to draw an equivalence between functors and classes in Scala. At the end the author is even forced to say:
This presents something that is definitely inspired by ML’s module system, but retains a bit more of Scala’s character.
I would not let this cloud your view of ML-functors, they are really significantly simpler and easier to understand and use than Scala classes.
I’m primarily a Haskell user, but I also dabble in OCaml. Going to agree here, ML functors are much easier to reason about than any attempt to emulate them I’ve seen in Scala.
I’d argue that the “approximately equal to” sign is quite a bit on the “approximately” side in this case, especially because it is not meant to say “a Scala class is a ML functor”, but “a specific usage of Scala classes can be used as a device to achieve the same concept for which you would use functors in ML”.
I recommend giving the talk a shot, I think it makes things more clear, and shows better how close ML’s and Scala’s module system are (although some of the issues described in Derek’s Modular Type Classes can be solved much better in Scala, so Scala is more like “almost ML plus X”).
EDIT: McQueen says “There is also a useful analogy viewing structures as objects and functors as classes.” in his paper http://sml-family.org/papers/MacQueen-reflections.pdf, p. 12.