[erlang-questions] Higher Order Modules
Zoltan Lajos Kis
kiszl@REDACTED
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