Simple solution: find
and join
It looks like you're looking for Data.List.find
. find
has the type signature
find :: (a -> Bool) -> [a] -> Maybe a
So you'd do something like
result :: Maybe (Maybe String)
result = find isJust [tryCombination x y | x <- [1..5], y <- [1..5]]
Or, if you don't want a Maybe (Maybe String)
(why would you?), you can fold them together with Control.Monad.join
, which has the signature
join :: Maybe (Maybe a) -> Maybe a
so that you have
result :: Maybe String
result = join $ find isJust [tryCombination x y | x <- [1..5], y <- [1..5]]
More advanced solution: asum
If you wanted a slightly more advanced solution, you could use Data.Foldable.asum
, which has the signature
asum :: [Maybe a] -> Maybe a
What it does is pick out the first Just
value from a list of many. It does this by using the Alternative
instance of Maybe
. The Alternative
instance of Maybe
works like this: (import Control.Applicative
to get access to the <|>
operator)
λ> Nothing <|> Nothing
Nothing
λ> Nothing <|> Just "world"
Just "world"
λ> Just "hello" <|> Just "world"
Just "hello"
In other words, it picks the first Just
value from two alternatives. Imagine putting <|>
between every element of your list, so that
[Nothing, Nothing, Just "okay", Nothing, Nothing, Nothing, Just "okay"]
gets turned to
Nothing <|> Nothing <|> Just "okay" <|> Nothing <|> Nothing <|> Nothing <|> Just "okay"
This is exactly what the asum
function does! Since <|>
is short-circuiting, it will only evaluate up to the first Just
value. With that, your function would be as simple as
result :: Maybe String
result = asum [tryCombination x y | x <- [1..5], y <- [1..5]]
Why would you want this more advanced solution? Not only is it shorter; once you know the idiom (i.e. when you are familiar with Alternative
and asum
) it is much more clear what the function does, just by reading the first few characters of the code.