[erlang-questions] Higher Order Modules

4 views
Skip to first unread message

ingo.schramm

unread,
Dec 14, 2009, 11:43:45 AM12/14/09
to erlang-q...@erlang.org
I wonder if parameterized modules are really intended to do OOP stuff
only. It seems to be possible to use this feature to implement
something like higher order modules, modules parameterized by other
modules.

As an example I could write a monoid module like this:

>>>
-module(monoid,[Impl]).
-export([op/2,cmp/2,get_id/0,get_member/0,is_member/1,proof/0]).

%% ------ INTERFACE -----

% apply monoid operation
op(A,B) ->
case members([A,B]) of
true -> Impl:op(A,B);
false -> undef
end.

% compare two values if they are equal or not
cmp(A,B) ->
case members([A,B]) of
true -> Impl:cmp(A,B);
false -> undef
end.

% get the identity or neutral element
get_id() ->
Impl:get_id().

% get an arbitrary member element
get_member() ->
Impl:get_member().

% test whether A is a member or not
is_member(A) ->
case Impl:is_member(A) of
true ->
Impl:is_member(Impl:op(A,Impl:get_id()));
false ->
false
end.

% give proof of monoid laws
proof() ->
prove_all()

%% ------ PRIVATE ------

prove() ->
I = Impl:get_id(),
A = Impl:get_member(),
B = A,
Op = prove_closed(A,B),
C = op(A,B),
Assoc = prove_assoc(A,B,C),
Id = prove_identity(N,A),
neg(lists:member(false,[Op,Assoc,Id])).

prove_closed(A,B) ->
Impl:is_member(Impl:op(A,B)).

prove_assoc(A,B,C) ->
Impl:op(Impl:op(A,B), C) =:= Impl:op(A, Impl:op(B,C)).

prove_identity(I,A) ->
0 =:= Impl:cmp(A,Impl:op(I,A)).

neg(true) -> false;
neg(false) -> true.

% empty set is always member
members([]) ->
true;
members(L = [A|_]) ->
neg(lists:member(false, [ is_member(X) || X <- L])).

<<<

Next I could write a module representing the additive monoid of
natural numbers (including zero):

>>>
-module(n_add).
-export([op/2,cmp/2,get_id/0,get_member/0,is_member/1]).

op(A,B) ->
A + B.

cmp(A,B) when A =/= B ->
-1;
cmp(A,B) when A =:= B ->
0.

get_id() ->
0.

get_member() ->
1.

is_member(A) when is_integer(A), A < 0 ->
false;
is_member(A) when is_integer(A), A >= 0 ->
true;
is_member(_A) ->
false.
<<<

And then I use it:
---
1> M = monoid:new(n_add).
{monoid,n_add}
2> M:proof().
true
3> M:op(1,2).
3
---

Another implementation may do matrix operations. It is also easy to
add more structure, for example to turn the monoid into a group by
adding op_inverse/2.

Does that make any sense?

Ingo

________________________________________________________________
erlang-questions mailing list. See http://www.erlang.org/faq.html
erlang-questions (at) erlang.org

Zoltan Lajos Kis

unread,
Dec 14, 2009, 12:08:12 PM12/14/09
to ingo.schramm, erlang-q...@erlang.org
Smells like the abstract factory pattern. Or is this dependency
injection ? :-)

Z.

ingo.schramm

unread,
Dec 14, 2009, 12:13:07 PM12/14/09
to erlang-q...@erlang.org
Or strategy? Or OCaml Functors?
:)
Ingo

> > erlang-questions mailing list. Seehttp://www.erlang.org/faq.html

Reply all
Reply to author
Forward
0 new messages