I have an input list
of type [Maybe SomeType]
and a predicate p
of type SomeType -> Bool
, and I want to answer the question "Does the predicate p
hold for all SomeType
s that happen to be in the input?".
The first part is easy: (map . fmap) p list
is of type [Maybe Bool]
.
One important info is that I know that length list >= 1
and all isNothing list == False
both hold, so there must be at least a Just True
in (map . fmap) p list
.
But how do I pull out one single Bool
out of that list?
I thought that I could take advantage of folding (e.g. via foldl
) and Maybe
's MonadPlus
instance, doing something like the following:
allTrueOrNothing :: [Maybe Bool] -> Bool
allTrueOrNothing = fromJust . foldl mplus mzero
but this is not quite true, because mplus
returns the left operand if it's Just something
regardless of what something
is, so allTrueOrNothing
will return True
even if its input is [Just True, Just False]
.
What's the cleanest/most idiomatic way I can accomplish the task?
I see that I could simply filter
out the Nothing
s and then and
together the Just
s, something like this:
allTrueOrNothing' :: [Maybe Bool] -> Bool
allTrueOrNothing' = all fromJust . filter (fmap not isNothing)
But I was more curious to know if there's a way to have those Maybe Bool
s behave like a Monoid
aware of its Bool
content.
Bookmark this question. Show activity on this post. Given an arbitrary list of booleans, what is the most elegant way of determining that exactly one of them is true? The most obvious hack is type conversion: converting them to 0 for false and 1 for true and then summing them, and returning sum == 1.
The bool type participates in default integral promotions. An r-value of type bool can be converted to an r-value of type int, with false becoming zero and true becoming one. As a distinct type, bool participates in overload resolution. Describes the purpose and use of user-defined literals in Standard C++.
In boolean logic, ANDing a collection of booleans is true if all of the booleans are true, ORing the collection is true if least one of them is true. Is there a logical construct that will be true if exactly one boolean is true? XOR is this for a collection of two booleans for example, but any more than that and it falls over.
Here we take input in boolean ( True/ False) in boolean type with bool () function and check whether it is returned true or false. user_input = bool(input("Are you hungry?
I would just use all
directly:
all . all :: (a -> Bool) -> [Maybe a] -> Bool
If you must have the phase distinction you describe for some reason, then you can use the specialization and = all id
:
all and :: [Maybe Bool] -> Bool
This seems to work:
> and . catMaybes $ [Just False, Nothing, Just False]
False
> and . catMaybes $ [Just False, Nothing, Just True]
False
> and . catMaybes $ [Just True, Nothing, Just True]
True
You can use catMaybes
to convert the list to [Bool]
, and and
to conclude.
(Note that this will return True
on an all-Nothing
s list, which is an "impossible" case according to your assumptions.)
If you absolutely want to use a monoid, I guess you can do that, but it's a bit cumbersome. It would involve to wrap each element of the list in some newtype And = And (Maybe Bool)
, then defining the relevant monoid instance, then mconcat
ing everying, and finally unwrapping.
Untested code:
newtype And = And (Maybe Bool)
instance Semigroup And where
And Nothing <> x = x
x <> And Nothing = x
And (Just a) <> And (Just b) = And (Just (a && b))
instance Monoid And where
mempty = Nothing
allTrueOrNothing :: [Maybe Bool] -> Bool
allTrueOrNothing = fromMaybe False . coerce . mconcat @And . coerce
The cleanest way is and . catMaybes
.
But you wanted to use Monoid that is aware of its Bool
content, in the &&
kind of way. That's All
:
> foldMap (fmap All) [Just True,Nothing,Just False]
Just (All {getAll = False})
> foldMap (fmap All) [Just True,Nothing,Just True]
Just (All {getAll = True})
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With