Monoid: Category == with { print: % -> (); times: (%, %) -> %; one: () -> %; equal?: (%, %) -> Boolean; } MonoidOfZ: Category == Monoid with { convert: Integer -> %; } OddNumbers: MonoidOfZ == add { attrib(n: Integer); convert(x: Integer): % == if (x rem 2 = 1) then attrib(x) else error; print(x: %): () == print (x.n); times(x: %, y: %): % == attrib((x.n) * (y.n)); one(): % == convert(1); equal?(x: %, y: %): Boolean == (x.n) = (y.n); } WordMonoid: Category == Monoid with { word: String -> %; } Word: WordMonoid == add { attrib(st: String, le: Integer); word(x: String): % == attrib(x, length(x)); print(x: %): () == print (x.st); times(x: %, y: %): % == { z: String := concat(x.st,y.st); l: Integer := x.le + y.le; attrib(z,l); } one(): % == word(empty(),0); equal?(x: %, y: %): Boolean == { if (x.le ~= y.le) then return false; equal?(x.st,y.st); } } main(): () == { x: Word := word("Hello "); y: Word := word("Mars."); xy: Word := times(x,y); print(xy); } main();Up to the magic function attrib, the program above could be a fragment of an ALDOR program. It declares three categories (or interfaces) and two domains (or classes). If you are an ALDOR user, you could be surprised by this attrib function: the goal here is to keep the grammar, the type checking and the translation simple!
Observe also that the above program relies on three built-in domains, namely Boolean, String and Integer.