10000 Suggestion: Cmd.flatten : Cmd<Cmd<'a>> -> Cmd<'a> · Issue #208 · elmish/elmish · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Suggestion: Cmd.flatten : Cmd<Cmd<'a>> -> Cmd<'a> #208

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
jwosty opened this issue Jul 29, 2020 · 4 comments
Open

Suggestion: Cmd.flatten : Cmd<Cmd<'a>> -> Cmd<'a> #208

jwosty opened this issue Jul 29, 2020 · 4 comments

Comments

@jwosty
Copy link
jwosty commented Jul 29, 2020

Description

May I suggest that Elmish have a Cmd.flatten function, which is the classic monadic flatten operation. Here is a complete implementation:

    let flatten (cmd: Cmd<Cmd<'a>>) : Cmd<'a> =
        [
            for (sub: ((Cmd<'a> -> unit) -> unit)) in cmd do
                (fun (dispatch: ('a -> unit)) ->
                    let dispatchCmd : Dispatch<Cmd<'a>> = fun (msg: Cmd<'a>) ->
                        for sub in msg do
                            sub dispatch
                    sub dispatchCmd
                )
        ]

Most recently, it let me mix and match various layers of Cmds and asyncs:

    let someAsyncFunction x = async { return x + 1 }
    type Msg = | SomeMsg of int | AnotherMsg
    let makeCmd x : Cmd<Msg> =
        let work = async {
            let! result = someAsyncFunction x
            return Cmd.ofSub (fun dispatch ->
                dispatch (SomeMsg result)
                dispatch AnotherMsg
            )
        }
        work |> Cmd.OfAsync.result |> Cmd.flatten

I can easily submit a PR for this with the above code; I just wanted to know if you would be likely to take it.

@forki
Copy link
Contributor
forki commented Jul 29, 2020 via email

@MangelMaxime
Copy link
Member

@forki I don't think Elm has this kind of helpers in it.

If I understand correctly your example. You are generating new Commands from inside a Command?

I think the standard approach is in general, to make this happen in the update function when receiving the initial success/error Msg.

I am mentioning it because I don't know if creating Commands inside of a Command is a problem or not.

@jwosty
Copy link
Author
jwosty commented Jul 29, 2020

@MangelMaxime you are correct -- however for the case that I based the example off of, it's really more of a situation where I wanted to dispatch multiple messages from inside the async. I could have alternatively written it manually like so (haven't checked this code in a compiler but it should be mostly right):

    let someAsyncFunction x = async { return x + 1 }
    type Msg = | SomeMsg of int | AnotherMsg
    let makeCmd x : Cmd<Msg> =
        Cmd.ofSub (fun dispatch ->
            Async.Start <| async {
                let! result = someAsyncFunction x
                dispatch (SomeMsg result)
                AnotherMsg
            }
        )

But I didn't really like the explicit Async.Start. I wanted to see if I could do it with Cmd functions directly, and it turns out to be impossible. An alternative might be to have some kind of Cmd.Async.returnMany which would dispatch a list of messages instead of a single message. Actually, having now written this, I'm realizing that I also could have written an "adapter" dispatch function that would just take a Msg list... So I guess there's many different ways to do this same thing. What would be the most Elmish-ish?

@et1975
Copy link
Member
et1975 commented Nov 28, 2021

@jwosty Can you see if this can be reimplemented with Cmd.batch?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants
0