[erlang-questions] Higher Order Modules

Zoltan Lajos Kis <>
Mon Dec 14 18:08:12 CET 2009


ingo.schramm wrote:
> 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
>
>   
Smells like the abstract factory pattern. Or is this dependency 
injection ? :-)

Z.


More information about the erlang-questions mailing list