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)