Josephine
Josephine

Reputation: 457

Haskell: catMaybe for Data.Set?

how would you implement a catMaybes for Data.Set ?

I came up with:

import qualified Data.Set as Set
import qualified Data.Maybe as Maybe
setCatMaybes a = Set.map Maybe.fromJust . Set.delete Nothing $ a

fnord = Set.fromList [Nothing, Just 41, Just 43, Just 47]

then i get the following

setCatMaybes fnord == fromList [41,43,47]

Upvotes: 1

Views: 896

Answers (4)

unhammer
unhammer

Reputation: 4740

λ> foldr (\a b -> maybe b (`Set.insert` b) a) Set.empty fnord
fromList [41,43,47]

Also works for other things so one could do a helper:

catMaybesF :: Foldable f => (a -> f a -> f a) -> f a -> f (Maybe a) -> f a
catMaybesF insert emptyf = foldr (\a b -> maybe b (`insert` b) a) emptyf

catMaybesSet = catMaybesF Set.insert Set.empty
catMaybesSeq = catMaybesF (Seq.:<|) Seq.empty

Upvotes: 1

pat
pat

Reputation: 12749

Since Set (Maybe a) is such a weird type, which appears only after the application of f :: a -> Maybe b, why not kill two birds with one stone and create a mapMaybe for Data.Set?

import qualified Data.Set
import qualified Data.Maybe

mapMaybe :: Ord b => (a -> Maybe b) -> Data.Set.Set a -> Data.Set.Set b
mapMaybe f = Data.Set.fromList . Data.Maybe.mapMaybe f . Data.Set.toList

In this way, the weird Set (Maybe a) never exists.

Upvotes: 3

Neil Brown
Neil Brown

Reputation: 3558

I think the solution you already have is probably the best one. Along the lines of John's solution, here's a fairly short one:

setCatMaybes :: Ord a => Set.Set (Maybe a) -> Set.Set a
setCatMaybes s = Set.fromAscList [x | Just x <- Set.toAscList s]

Or here's a longer one, that may be faster:

setCatMaybes2 :: Ord a => Set.Set (Maybe a) -> Set.Set a
setCatMaybes2 s
  | Set.null s = Set.empty
  | otherwise  = Set.mapMonotonic Maybe.fromJust $ case Set.deleteFindMin s of
                   (Nothing, s') ->  s'
                   _ -> s

Upvotes: 3

John L
John L

Reputation: 28097

How about just this:

setCatMaybes = Set.fromList . catMaybes

This will only require traversing the list once, as Set.fromList is a good consumer.

Upvotes: 0

Related Questions