pmod_pt added for parameterized module support #12

Closed
wants to merge 1 commit into
from

Projects

None yet

8 participants

lemenkov commented Mar 2, 2013

Better and cleaner version of pull #11

voluntas commented Mar 8, 2013

I tried with "R16B" this fix. However, I was not able to compile the following error out. Are you able to compile correctly in your environment? It is good if the only bad my environment.

src/state_t.erl:21: undefined callback function '>>='/2 (behaviour 'monad')
src/state_t.erl:21: undefined callback function fail/1 (behaviour 'monad')
src/state_t.erl:21: undefined callback function return/1 (behaviour 'monad')

I tried the patch with "R16B" and got same errors that @voluntas had. But I noticed that if I comment out -behaviour(monad). in state_t.erl and error_t.erl, they will compile and work as expected.

I compared the results of new/0 and module_info/0 with both R15B03-1 with parameterized module and R16B with pmod_pt. I found they look same.

Erlang R16B (erts-5.10.1) [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false]

Eshell V5.10.1  (abort with ^G)
1> St = state_t:new(identity).
{state_t,identity}

2> error_t:module_info().
[{exports,[{'>>=',3},
           {return,2},
           {fail,2},
           {run,2},
           {lift,2},
           {new,1},
           {instance,1},
           {module_info,0},
           {module_info,1}]},
...

3> state_t:module_info().
[{exports,[{'>>=',3},
           {return,2},
           {fail,2},
           {get,1},
           {put,2},
           {eval,3},
           {exec,3},
           {run,3},
           {modify,2},
           {modify_and_return,2},
           {lift,2},
           {new,1},
           {instance,1},
           {module_info,0},
           {module_info,1}]},
 ...

new/0 returns a module tuple such as {state_t,identity} and all other functions got an extra parameter.

For example, this is the original function definition in state_t.erl:

-export(['>>='/2, return/1, fail/1]).

'>>='(X, Fun) -> fun (S) -> do([InnerMonad || {A, S1} <- X(S),
                                              (Fun(A))(S1)]) end.

and this is what module_info says:

[{exports,[{'>>=',3},

The last parameter should be for receiving the module tuple, so I think the function is transformed into:

-record(?MODULE, {mod :: module()}).

'>>='(X, Fun, #?MODULE{mod=InnerMonad}) ->
    fun (S) -> do([InnerMonad || {A, S1} <- X(S),
                                 (Fun(A))(S1)]) end.

I think pmod_pt is working as expected, but difference between R15B03-1 and R16B is behaviour part. Does anybody know how to deal with this?

@tatsuya6502 tatsuya6502 referenced this pull request in erlang/pmod_transform Mar 11, 2013
Open

behaviour won't work on a module transformed by pmod_pt #2

Contributor

Guys - I'll take a look at this ASAP. We're no longer using erlando in RabbitMQ, so it's taken a while a to get around to.

@hyperthunk hyperthunk referenced this pull request May 7, 2013
Closed

R16B support #13

@hyperthunk - thank you for looking after this issue. Please let me know if you need anything from me.

Contributor

Sure, will do.

I went and update the code to just work with 'stateful modules' -- the code for 'state_t' is included below. 'error_t' is simpler and can be easily update from the 'state_t' example. Running the test code under R16B also exposed an issue with the 'test.erl' code; and I have included the change. The updated code will now run on R16B and earlier versions.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%% The contents of this file are subject to the Mozilla Public License
%% Version 1.1 (the "License"); you may not use this file except in
%% compliance with the License. You may obtain a copy of the License
%% at http://www.mozilla.org/MPL/
%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and
%% limitations under the License.
%%
%% The Original Code is Erlando.
%%
%% The Initial Developer of the Original Code is VMware, Inc.
%% Copyright (c) 2011-2013 VMware, Inc. All rights reserved.
%%

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%

%* Converted from 'Parameterized Module' to 'Stateful Module'
%*
%* Parameterized Modules auto-add a 'new' fun
%* X = module:new( P1, P2 ).
%*
%* X is actually {module, P1, P2} -- just like the stateful module syntax, but
%* we have to handle the extraction of the tuple, whereas the pmod code was
%* taking care of that for us.
%*
%* So we need to:
%* Change the -module back to a standard erlang module.
%* Add a 'new' fun to simulate the auto-created one by the parameterized module.
%* Change all calls made through the returned 'instance' to take the additional
%* 'state' param -- we simplify this by using a define.
%* Update the arity of all of these calls.
%*
%* We also remove -behavior(monad) because of the updated arity to '>>=', fail & return.
%*
%*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%* -module(state_t, [InnerMonad]).
%* -behaviour(monad).
%* -export(['>>='/2, return/1, fail/1]).
%* -export([get/0, put/1, eval/2, exec/2, run/2,
%* modify/1, modify_and_return/1, lift/1]).

-module(state_t).
-compile({parse_transform, do}).

-export([new/1]).
-export(['>>='/3, return/2, fail/2]).
-export([get/1, put/2, eval/3, exec/3, run/3,
modify/2, modify_and_return/2, lift/2]).

-ifdef(use_specs).
-type(monad(A) :: fun ((S) -> {A, S})).
-include("monad_specs.hrl").
-endif.

%* Create a define for simplification -- may be multiple parameters.
-define( PMOD_FIX, {?MODULE, InnerMonad} ).

%* Add the 'new' fun.
new( InnerMonad ) -> ?PMOD_FIX.

'>>='(X, Fun, ?PMOD_FIX) -> fun (S) -> do([InnerMonad || {A, S1} <- X(S),
(Fun(A))(S1)]) end.

return(A, ?PMOD_FIX) -> fun (S) -> InnerMonad:return({A, S}) end.
fail(Str, ?PMOD_FIX) -> fun (_) -> InnerMonad:fail(Str) end.

get(?PMOD_FIX) -> fun (S) -> InnerMonad:return({S, S}) end.

put(S, ?PMOD_FIX) -> fun (_) -> InnerMonad:return({ok, S}) end.

eval(Monad, S, ?PMOD_FIX) -> do([InnerMonad || {A, _S1} <- Monad(S),
return(A)]).

exec(Monad, S, ?PMOD_FIX) -> do([InnerMonad || {_A, S1} <- Monad(S),
return(S1)]).

%* Had to hand fix this because we nolonger have the monad behaviour; was causing 'unused' error.
%* run(Monad, S, ?PMOD_FIX) -> do([InnerMonad || Monad(S)]).
run(Monad, S, _PMOD_FIX) -> Monad(S).

modify(Fun, ?PMOD_FIX) -> fun (S) -> InnerMonad:return({ok, Fun(S)}) end.

modify_and_return(Fun, ?PMOD_FIX) -> fun (S) -> InnerMonad:return(Fun(S)) end.

lift(X, ?PMOD_FIX) -> fun (S) -> do([InnerMonad || A <- X, return({A, S})]) end.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

test_funs(ErrorT, [{Module, FunName}|Funs])
when is_atom(Module) andalso is_atom(FunName)
%* andalso is_function({Module, FunName}, 0) ->
%* In earler versions (at least in R14B) is_function would return
%* 'true' for almost any two elem tuple i.e.
%* 1> is_function({foo,bar},99).
%* true
->
case erlang:function_exported(Module, FunName, 0) of
true ->
do([ErrorT || hoist(ErrorT, FunName, fun () -> Module:FunName() end),
test_funs(ErrorT, Funs)]);
false -> error(illegal)
end;

BartAdv commented Jun 15, 2014

I've only added monad_t behaviour with different arities on top of pmod_pt and everything worked well: BartAdv@ebd1de6, however, it doesn't work when transformer calls 'normal' function...

@dumbbell dumbbell modified the milestone: n/a Mar 24, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment