Skip to content
This repository was archived by the owner on Aug 30, 2019. It is now read-only.

pmod_pt added for parameterized module support #12

Closed
wants to merge 1 commit into from

Conversation

lemenkov
Copy link

@lemenkov lemenkov commented Mar 2, 2013

Better and cleaner version of pull #11

@voluntas
Copy link

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')

@tatsuya6502
Copy link

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?

@hyperthunk
Copy link
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 mentioned this pull request May 7, 2013
@tatsuya6502
Copy link

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

@hyperthunk
Copy link
Contributor

Sure, will do.

@ghost
Copy link

ghost commented Jan 9, 2014

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
Copy link

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 subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants