Other than the syntax, I’m not sure I understand how this is different from any other object-oriented class definition. I suppose the ability to project the module into the local or top-level scope, but that seems more like syntactic sugar than anything meaningful. What am I missing here?
As another answer pointed out, a class in OOP is supposed to implement only one type and operations on it. It works in many cases, but sometimes it does not fit naturally the problem at hand. Modules relax this single-type requirement, and let you define multiple types in it, which makes certain things more natural to express, without a need to create multiple shallow classes or manager-like classes. Also, functors (…
Exotic Programming Ideas: Module Systems
31–40 of 57 posts
Re: Exotic Programming Ideas: Module Systems
#32Earlier quoted context omitted.
I'm trying to wrap my head around this > Even better, you can define relations between the types and do type substitutions, e.g.: to construct this module, you need to give me 2 other modules, each with a specific set of functions, and for which type t1 of the first module, matches type t2 of the second module, while the actual type of t1/t2 does not matter. Isn't this essentially the same as generic type arguments i…
It's not exactly the same thing because, for example, there is no subtyping or inheritance. In Ocaml you don't say that "type T1 is an Orderable". However, it does serve a similar purpose. For example, if you want to create a datatype for an OrderedList then you'd create a higher-order-module (functor) that receives as an argument another module containing all the necessary comparison functions for the list elements.…
Re: Exotic Programming Ideas: Module Systems
#33Earlier quoted context omitted.
As another answer pointed out, a class in OOP is supposed to implement only one type and operations on it. It works in many cases, but sometimes it does not fit naturally the problem at hand. Modules relax this single-type requirement, and let you define multiple types in it, which makes certain things more natural to express, without a need to create multiple shallow classes or manager-like classes. Also, functors (…
I think Lisp's object system (CLOS) removes this limitation? (Actually a question - I believe this is what multiple dispatch does, but not certain)
module Data = struct
type pair = int * float
type numbers = int list
let make_pair () = (0, 0.0)
let make_numbers () = []
end
This example is not very illustrative, but just explain the idea what I mean. We have two constructors: make_pair and make_numbers. So in a way, we can have multiple types in the module, if they are meant to be tightly related. We are not forced to make three classes here (Pair, Numbers, Data), everything is in one module.EDIT: OOP classes have a primary type in your class, and sometimes this creates artificial chicken or egg type of problem, where you cannot decide what is more fundamental (message vs receiver vs sender). Modules don't force this on you.
Re: Exotic Programming Ideas: Module Systems
#34A big helper is when the module interface uses named parameters and has sensible defaults for unspecified parameters. This allows the module designer to add features without breaking existing code and makes it easier for someone to integrate the module in the first place. Having the documentation built into the module itself is also a huge win.
Re: Exotic Programming Ideas: Module Systems
#35Coming in without much OCaml experience, I don't really think this is a great demonstration of why this construct has value. I don't really want to read a long form description of the OCaml implementation of modules. I want a comparison to the languages he dismissed at the beginning of the article, and a discussion of why this feature has some value that isn't provided by those languages. Basically - This feels like…
interface Mappable {
map(f: (a: A) => B, fa: Array): Array
}
Likewise, for `Promise`s we could write: interface Mappable {
map(f: (a: A) => B, fa: Promise): Promise
}
But in order to generalize this interface to an arbitrary type constructor such that `F: * -> *`, we would need to write interface Mappable {
map(f: (a: A) => B, fa: ?): ?
}
which is not possible in TypeScript since it does not support higher-kinded types or type parameters that take type parameters or parametrized modules.Re: Exotic Programming Ideas: Module Systems
#36Earlier quoted context omitted.
For me, the value of a module is that you can describe a set of multiple types and the functions that operate on these types, all in one place. In OO, there is essentially one type that is "special", the type of the class you define. The power of the Ocaml module system is really in the functor, which the article only touches upon. You define a module and refer in its definition to types/functions of other modules th…
I'm trying to wrap my head around this > Even better, you can define relations between the types and do type substitutions, e.g.: to construct this module, you need to give me 2 other modules, each with a specific set of functions, and for which type t1 of the first module, matches type t2 of the second module, while the actual type of t1/t2 does not matter. Isn't this essentially the same as generic type arguments i…
Here's an example. This example is a bit contrived, because I couldn't think of a better example that was simple and yet demonstrated the power of modules. So this example can be re-phrased and re-structured into a more natural OO fit, but try to look past that. Suppose you want to make a module or set of interfaces that describe a classic board game (i.e. Chess or Checkers). So you have a Board. A Board has a series of Pieces, and each Piece has a set of valid moves on the board. And a move can be applied to a Board to modify the state of the game. Again, very much glossing over the details here to get to the meat of it. So you could write a series of interfaces
interface Board {
List getPieces();
}
interface Piece {
List getValidMoves(b: Board);
}
interface Move {
void apply(b: Board);
}
But on it's own that isn't enough, because you don't want to be able to mix-and-match different interfaces for different games, like trying to find the set of valid moves for a chess piece on a checker board. So you need to apply generics. interface Board {
List
getPieces();
}
interface Piece {
List getValidMoves(b: B);
}
interface Move {
void apply(b: B);
}
Only that's not enough either, because on it's own these parametric definitions don't enforce that the set of pieces a board returns are actually valid pieces for that game. With constraints you end up with this (in a psuedo-language where you can use a special Self type, I don't know typescript and don't think this can actually be implemented in plain Java) interface Board>> {
List getPieces();
}
interface Piece, M extends Move> {
List getValidMoves(b: B);
}
interface Move> {
void apply(b: B);
}
And so you have a bunch of these weird circular definitions to get these components to play together nicely. Meanwhile, you can define a module for this without using Functors or type substitutions or anything terribly complicated (Note the below is sort of mixing OCaml with more Java-like syntax just because I'm not super familiar with OCaml): module type Game = sig
type Board
type Piece
type Move
val getPieces: Board -> List
val getValidMoves: Piece -> Board -> List
val apply: Move -> Board -> unit
end
And I think that's the really interesting thing you can do with modules that is more awkward with the traditional OOP interfaces. It makes it more natural to talk about multiple different data types all working together.The only way to implement that as nicely with an OOP interface would be to wrap everything in a top-level object
interface Game {
List getPieces(b: B);
List getMoves(p: P, b: B);
void apply(m: M, b: B);
}
Though now you have to make a singleton Game object and pass that around everywhere you need it, which may or may not be idiomatic or obvious depending on the language and your preferences.Re: Exotic Programming Ideas: Module Systems
#37Earlier quoted context omitted.
It's not exactly the same thing because, for example, there is no subtyping or inheritance. In Ocaml you don't say that "type T1 is an Orderable". However, it does serve a similar purpose. For example, if you want to create a datatype for an OrderedList then you'd create a higher-order-module (functor) that receives as an argument another module containing all the necessary comparison functions for the list elements.…
This makes it seem like modules are strictly inferior, if you can't assign names to common requirements.
module type Comparable = sig
type t
val compare : t -> t -> int
endRe: Exotic Programming Ideas: Module Systems
#38Earlier quoted context omitted.
For me, the value of a module is that you can describe a set of multiple types and the functions that operate on these types, all in one place. In OO, there is essentially one type that is "special", the type of the class you define. The power of the Ocaml module system is really in the functor, which the article only touches upon. You define a module and refer in its definition to types/functions of other modules th…
I'm trying to wrap my head around this > Even better, you can define relations between the types and do type substitutions, e.g.: to construct this module, you need to give me 2 other modules, each with a specific set of functions, and for which type t1 of the first module, matches type t2 of the second module, while the actual type of t1/t2 does not matter. Isn't this essentially the same as generic type arguments i…
Probably closer would be (not sure if this is possible in Typescript):
class CustomModule, T2 extends Module2Interface > {
constructor(t1: T1, t2: T2) { ... }
}
Meaning that, for example, within Module1Inteface, there is some function f1 that returns an S, and within Module2Interface, there is some function f2 that takes an S as argument.This does become a bit tedious notation-wise, if possible at all. In Ocaml, this would look like:
module CustomModule(M1: Module1)(M2: Module2 with type s = M1.s)Re: Exotic Programming Ideas: Module Systems
#39Coming in without much OCaml experience, I don't really think this is a great demonstration of why this construct has value. I don't really want to read a long form description of the OCaml implementation of modules. I want a comparison to the languages he dismissed at the beginning of the article, and a discussion of why this feature has some value that isn't provided by those languages. Basically - This feels like…
Say you'd like to have an interface for things that are 'mappable'. For example, for arrays we could write: interface Mappable { map (f: (a: A) => B, fa: Array ): Array } Likewise, for `Promise`s we could write: interface Mappable { map (f: (a: A) => B, fa: Promise ): Promise } But in order to generalize this interface to an arbitrary type constructor such that `F: * -> *`, we would need to write interface Mappable {…
interface Mappable, T> {
flatMap(f: (x: T) => Mappable): Mappable;
}
class Maybe implements Mappable, T> {
x: T | undefined;
public flatMap(f: (x: T) => Maybe): Maybe {
if (this.x) {
return f(this.x);
}
return Maybe.nothing();
}
}Re: Exotic Programming Ideas: Module Systems
#40Coming in without much OCaml experience, I don't really think this is a great demonstration of why this construct has value. I don't really want to read a long form description of the OCaml implementation of modules. I want a comparison to the languages he dismissed at the beginning of the article, and a discussion of why this feature has some value that isn't provided by those languages. Basically - This feels like…
Say you'd like to have an interface for things that are 'mappable'. For example, for arrays we could write: interface Mappable { map (f: (a: A) => B, fa: Array ): Array } Likewise, for `Promise`s we could write: interface Mappable { map (f: (a: A) => B, fa: Promise ): Promise } But in order to generalize this interface to an arbitrary type constructor such that `F: * -> *`, we would need to write interface Mappable {…