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

new function `existsAnd : (a -> Bool) -> Maybe a -> Bool`

skyqrose opened this issue · comments

Maybe is basically a List with 0 or 1 elements. All the functions in List and Haskell's Foldable class have equivalents in Maybe or Maybe.Extra, or don't make sense with only 1 element, except for fold (which is handled by #55) and any/all.

The difference between any and all for Maybe would be in the empty case.

any : (a -> Bool) -> Maybe a -> Bool
any predicate mx =
  case mx of
    Nothing -> False
    Just x -> predicate x

all : (a -> Bool) -> Maybe a -> Bool
all predicate mx =
  case mx of
    Nothing -> True
    Just x -> predicate x

I think this is a pretty simple thing to want to do that Maybe and Maybe.Extra don't support right now. There isn't really a good way to run a predicate on a Maybe. You could do filter predicate >> isJust or map predicate >> withDefault False, but those don't really express the idea of "do I have something that matches" well.

I found several examples of people implementing any with a variety of names:
exists
extractBool
existsAnd
(??)
maybePredicate
maybePredicate

I saw no examples of people implementing all.

I propose adding a single new function for any, but with a different name that's less list-like and more maybe-like. Maybe existsAnd or isJustAnd. I think those names would look good in a pipeline.

[1, 2, 3]
|> List.head
|> Maybe.Extra.existsAnd isEven

Thoughts?

I've tried various streaming's versions of the functions to make

https://github.com/NeilW/elm-orderbook/blob/master/src/OrderBook.elm#L192

clearer, but nothing is as clear as writing it out. And even that's not that clear :-)

I actually want all here I think, Along with something to do Bool -> a -> Maybe a

which would perhaps allow a curry

buyMaybeFillable activeBuy =
Maybe.Extra.all ("<=" passiveSell.price) activeBuy.price
    |> Maybe.Extra.toMaybe

That Bool -> a -> Maybe a function was considered here: #49 It was ultimately rejected, because

It slightly encourages invalid states. For example, there's an implicit assumption that's not reflected in the types that guarded (not << List.isEmpty) will never return Just []. A safer way to model the types would be a Maybe Nonempty or just passing the List through and casing on the format later.

That would suggest using config.isFillable : ... -> Bool

buyIsFillable : OrderRequest -> ( Order, Heap Order ) -> Bool
buyIsFillable activeBuy ( passiveSell, _newSell ) =
    Maybe.Extra.all (\buyPrice -> buyPrice >= passiveSell.price) activeBuy.price

...

config.getpassiveQueue book
    |> Heap.pop
    |> Maybe.Extra.filter (config.isFillable activeRequest)

But I see the need for all here. And even if it only gets a little use, having an any/all pair could make both of them clearer and help people think about what the right thing to do with the nothing case is. So we'd just need a pair of names that makes their similarities and differences clear. Some ideas:

  • any/all (Not clear what they mean if you don't see the similarities to List)
  • testAndIsJust/testOrIsNothing
  • isJustAndPasses/isNothingOrPasses
  • predicateDefaultFalse/predicateDefaultTrue
  • existsAnd / notExistsOr
  • isJustAnd / isNothingOr

With the last two fitting nicely with the existing isJust and isNothing function names