elm-community / maybe-extra

Convenience functions for working with Maybe.

Home Page:http://package.elm-lang.org/packages/elm-community/maybe-extra/latest

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Proposal: `oneOf`

TSFoster opened this issue · comments

Hi,

I wondered if you'd be interested in a pull request to add oneOf? Either …

oneOf : List (a -> Maybe b) -> Maybe a -> Maybe b

… or …

oneOf : List (a -> Maybe b) -> a -> Maybe b

So the function keeps applying a to the first function in the list, until it gets Just something:

f : Maybe String -> Maybe String -- or String -> Maybe String
f =
    oneOf
        [ always Nothing
        , \s -> if String.length s < 5 then Just s else Nothing
        , String.uncons >> Maybe.map Tuple.second
        ]

f (Just "hello world") == Just "ello world" -- or f "hello world"
f (Just "hi") == Just "hi" -- or f "hi"
f (Just "") == Nothing -- or f ""
f Nothing == Nothing -- N/A

If so, which of the type definitions would be a better fit? I personally prefer the second definition.

Ha, I was just gonna propose the same thing. Here's my working version:

oneOf : a -> List (a -> Maybe b) -> Maybe b
oneOf arg fList =
    -- given an arg and list of functions, apply
    -- functions in order until you get a `Just`
    -- result
    case fList of
        [] ->
            Nothing

        f :: rest ->
            case f arg of
                Just v ->
                    Just v

                Nothing ->
                    oneOf arg rest

I put arg first, but I don't feel passionately about that.

My use case was I had a bunch of small things that were wrapping Parser. I probably could have restructured my code to have a massive Parser.oneOf thingy, but some of the individual parsers were kinda ad hoc.

I think putting the List first reads best, will work best with |> piping, and keeps it most consistent with use of oneOf in other published packages.

If this seems like it could be a good addition, I would be happy to create a PR adding it?

I totally agree on flipping, for exactly the reason you mention. Here's the new version:

oneOf : List (a -> Maybe b) -> a -> Maybe b
oneOf fList arg =
    -- given a list of functions and an arg, apply
    -- functions in order until you get a `Just`
    -- result
    case fList of
        [] ->
            Nothing

        f :: rest ->
            case f arg of
                Just v ->
                    Just v

                Nothing ->
                    oneOf rest arg

Here's how I use it:

    url.fragment
        |> Maybe.andThen (oneOf [ parseTree, parsePage ])

@TSFoster It would great if you created the PR.

Done (#47). Renamed the arguments to be more in line with the style used in the rest of the package. And I also used a different example in the docs (that's a perfect use case, but the other examples are testable with elm-verify-examples, short and only use core modules)

Done by #47