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 returnJust []
. A safer way to model the types would be aMaybe Nonempty
or just passing theList
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