GithubHelp home page GithubHelp logo

Comments (6)

msackman avatar msackman commented on July 21, 2024
test_sequence() ->
    List = lists:seq(1,5),
    ListM = [do([maybe_m || return(io:format("~p~n", [N])),
                            return(N)]) || N <- List],
    {just, List} = monad:sequence(maybe_m, ListM).

does indeed print out the numbers 1 to 5, in that order.

sequence is a pretty direct translation of the Haskell version at http://www.haskell.org/ghc/docs/latest/html/libraries/base/src/Control-Monad.html#sequence
That too, uses foldr. Whilst the list is indeed traversed from right to left, don't forget that you're actually the evaluation as part of the list construction, and that is done left to right. It is only the combination of the results that is done by sequence. So for example:

test_sequence() ->
    List = lists:seq(1,5),
    ListM = [do([maybe_m || return(io:format("~p~n", [N])),
                            return(N)]) || N <- List],
    io:format("HERE~n"),
    {just, List} = monad:sequence(maybe_m, ListM).

here, you get the numbers printed out first, then HERE. Does that make sense?

from erlando.

msackman avatar msackman commented on July 21, 2024

There is an interesting issue though with more complex monads where "values" are actually functions. For example, compare the difference between:

test_sequence() ->
    StateT = state_t:new(identity_m),
    List = lists:seq(1,5),
    ListM = [do([StateT || return(io:format("~p~n", [N])),
                           return(N)]) || N <- List],
    io:format("HERE: ~p~n", [ListM]),
    io:format("~p~n", [StateT:run(monad:sequence(StateT, ListM), undefined)]).

and

test_sequence() ->
    StateT = state_t:new(identity_m),
    List = lists:seq(1,5),
    ListM = [do([StateT || return(true),
                           return(io:format("~p~n", [N])),
                           return(N)]) || N <- List],
    io:format("HERE: ~p~n", [ListM]),
    io:format("~p~n", [StateT:run(monad:sequence(StateT, ListM), undefined)]).

In the do transform, the construction of the list will actually force the evaluation of the argument to the first return. So even though in both cases, ListM will be a list of functions, in the first example, you'll get the numbers printed out before the HERE, but not in the second case.

In the first case, as the io:format is performed as part of list construction, it's easy to see it happens left to right. In the second case, it occurs only as a result of the StateT:run call. Whilst sequence does iterate right-to-left through the list, don't forget the list is a list of functions, and thus sequence itself must return a function too - itself, it is not really doing any work at all. So if you then look at the nature of the function that sequence will return, you'll see that the "current" value is forced before the accumulator: ultimately you'll end up with a series of nested functions, one per list element, and the outer-most will correspond to the first element of the list (and was constructed last, due to the use of foldr). It is then only when you hit the StateT:run (or eval or exec) that the outer-most function will be invoked, and evaluation will the ripple down.

from erlando.

kinogmt avatar kinogmt commented on July 21, 2024

I'm just curious about the monad:sequence/2's order of evaluation for monads with side effects like below.
it looks like evaluating right to left.

And I also believe haskell's sequence evaluates left to right as written in the document ---
"...Evaluate each action in the sequence from left to right, and collect the results... ".

Yes, haskell's sequence is also using foldr, but it is not strict. Their foldr is just right associative
and it does not affect the order of evaluation.

% cat src/seffect_m.erl
-module(seffect_m).
-compile({parse_transform, do}).
-behaviour(monad).
-export(['>>='/2, return/1, fail/1,
         test_do/0, test_seq/0]).

'>>='(X, Fun) ->
    io:format(":::~p:::~n", [X]),
    Fun(X).

return(X) -> X.
fail(X)   -> throw({error, X}).

%% --- test ---
test_do() ->
    M0 = abc,
    M1 = def,
    do([seffect_m || V0 <- M0, V1 <- M1, return([V0, V1])]).

test_seq() ->
    M0 = abc,
    M1 = def,
    monad:sequence(seffect_m, [M0, M1]).

% erl -pz ./ebin
Erlang R14B01 (erts-5.8.2) [source] [64-bit] [smp:2:2] [rq:2] [async-threads:0] [hipe] [kernel-poll:false]

Eshell V5.8.2  (abort with ^G)
1> seffect_m:test_do().
:::abc:::
:::def:::
[abc,def]
2> seffect_m:test_seq().
:::def:::
:::[]:::
:::abc:::
:::[def]:::
[abc,def]
3> 

from erlando.

msackman avatar msackman commented on July 21, 2024

I think this is fixed in the above commit - certainly my testing and thinking supports this. I'm quite pleased that the implementation I've come up with is both tail-call based and does not use ++. Please let me know if this works for you.

from erlando.

msackman avatar msackman commented on July 21, 2024

Mmm, I wonder if the same issue occurs in monad_plus:msum, and maybe also the "real" implementation of >>= in list_m.

from erlando.

kinogmt avatar kinogmt commented on July 21, 2024

I repeated the same small example in my comment above. Yes, it is now left to right. Thanks.

% erl -pz e bin
Erlang R14B01 (erts-5.8.2) [source] [64-bit] [smp:2:2] [rq:2] [async-threads:0] [hipe] [kernel-poll:false]

Eshell V5.8.2  (abort with ^G)
1> seffect_m:test_seq().
:::abc:::
:::def:::
[abc,def]
2>

from erlando.

Related Issues (11)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.