Optimize mapOptional and add more efficient findOptional (#9214)

* Optimize mapOptional and add more efficient findOptional

Given that we don’t have list fusion catOptionals . map f is clearly
less efficient than this version.

I also added findOptional which can be pretty handy in certain cases.

changelog_begin
changelog_end

* more foldr

changelog_begin
changelog_end

* fix tests

changelog_begin
changelog_end
This commit is contained in:
Moritz Kiefer 2021-03-23 18:07:45 +01:00 committed by GitHub
parent 1e0c67c306
commit 90c5ce703a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 25 additions and 1 deletions

View File

@ -68,10 +68,24 @@ isNone = not . isSome
-- the result list. If it is `Some b`, then `b` is included in the
-- result list.
mapOptional : (a -> Optional b) -> [a] -> [b]
mapOptional f = catOptionals . map f
mapOptional p = foldr f []
where f x acc = case p x of
None -> acc
Some y -> y :: acc
-- | Perform some operation on `Some`, given the field inside the
-- `Some`.
whenSome : Applicative m => Optional a -> (a -> m ()) -> m ()
whenSome None _ = pure ()
whenSome (Some v) f = f v
-- | The `findOptional` returns the value of the predicate at the first
-- element where it returns `Some`. `findOptional` is similar to `find` but it
-- allows you to return a value from the predicate. This is useful both as a more
-- type safe version if the predicate corresponds to a pattern match
-- and for performance to avoid duplicating work performed in the predicate.
findOptional : (a -> Optional b) -> [a] -> Optional b
findOptional _ [] = None
findOptional p (x :: xs) = case p x of
None -> findOptional p xs
Some y -> Some y

View File

@ -76,3 +76,13 @@ testWhenSome = scenario do
submit p (fetch cid)
whenSome (Some 5) (\x -> submit p $ exercise cid $ ConsumeIfPositive x cid)
submitMustFail p (fetch cid)
testFindOptional = scenario do
findOptional toLeft [] === (None : Optional ())
findOptional toLeft [Right 1] === (None : Optional ())
findOptional toLeft [Right 1, Left 2] === Some 2
findOptional toLeft [Right 1, Left 2, Left 3] === Some 2
toLeft : Either a b -> Optional a
toLeft (Left a) = Some a
toLeft (Right _) = None