3 ms·
> I don't find myself missing modules that much for precisely the inverse reason. The “tiny” detail is that ML modules do much more than what type classes do:
by catnaroek 11y ago
> I don't find myself missing modules that much for precisely the inverse reason.
The “tiny” detail is that ML modules do much more than what type classes do: they allow you to define abstract types whose representation is invisible to the rest of the program, without ugly hacks like `newtype`-wrapping the internal representation.
> If Haskell+Backpack had first class packages/modules
Packages and modules are completely different things. A package is a unit of distribution, whereas a module is a unit of encapsulation. Even within a single program that's only distributed as a whole, you may want different components to hide their internals from each other.
> This is the duality I am trying to get it
There is no duality between modules and type classes, because, while modules can do everything type classes do (and more), the converse does not hold.
- Ericson2314 11y agoRemember, it's the combination of type classes and higher kinded types that the MLs are up against. [Not because there is an inherent trade-off (because there isn't one between type classes vs modules either as the Dryer paper shows), but beause the MLs have that weakness.]
- catnaroek 11y agoNon-recursive higher-kinded types can be implemented in terms of functors. For example, the free monad type constructor is very easy to implement in Standard ML (OCaml is similar): signature FUNCTOR = sig type 'a t val map : ('a -> 'b) -> 'a t -> 'b t end functor FreeMonad (F : FUNCTOR) = struct datatype 'a t = Pure of 'a | Free of 'a t F.t (* operations go here *) end Modules can do everything type classes can do, and more. There is no weakness. The real reason why you need to define this as a higher-kinded type constructor in Haskell (`data Free f a = ...`) is to overcome the limitation of not having parameterized modules. The way it's done in Haskell also has the defect that the type system will happily allow you to construct a value of type `Free Foo a`, where `Foo` is not a functor, whereas the ML version prohibits this by construction.
- Ericson2314 11y agoThat's not the same however, because the modules language is a lot more constrained than the term language. See the first paragraph the second page of https://www.mpi-sws.org/~rossberg/1ml/1ml-extended.pdf https://www.mpi-sws.org/~rossberg/1ml/1ml-extended.pdf.
- catnaroek 11y ago> That's not the same however, because the modules language is a lot more constrained than the term language. You don't need to tell me. That's obvious to anyone who has programmed in ML. But Haskell's type class language is similarly a lot more constrained than its term language. It's basically a pure (in particular, cut-free) compile-time Prolog, with some restrictions to guarantee that no query will return more than one result. > See the first paragraph the second page of https://www.mpi-sws.org/~rossberg/1ml/1ml-extended.pdf https://www.mpi-sws.org/~rossberg/1ml/1ml-extended.pdf. Rest assured, I've read the paper - not today, but several months ago. I'm quite familiar with the ML module literature. Check my post history: https://news.ycombinator.com/item?id=10856201 https://news.ycombinator.com/item?id=10856201 https://news.ycombinator.com/item?id=11131265 https://news.ycombinator.com/item?id=11131265 But, since you're arguing that the combination of type classes and higher-kinded types can do something that ML modules can't, I'm providing evidence for the opposite: everything that can be done with type classes and higher-kinded types can be done with modules. (0) You can't compute new modules at runtime, but you also can't define new type class instances at runtime. (1) An ML module can have both transparent and abstract type components, controlled by the programmer. A type class always has abstract type components at definition time, and transparent type components at instantiation time. Modules are more expressive than type classes. (2) The signature of an ML module is structural, and you can, after the fact, selectively forget part of a module's contents. Type classes don't let you do this. Try making `Monoid` a subclass of `Semigroup` without recompiling any existing code. Again, modules are more expressive than type classes. As for higher kinds, at least with OCaml's higher-order applicative functors, you can encode arbitrary higher-kinded type constructors. And most of the higher-kinded constructors that actually arise in practice can be encoded even with Standard ML's first-order functors.