Reputation: 2738
I want to write something like this:
> [(i, j) | i <- [1..10],
Just j <- [if (even i) then Just (i `div` 2) else Nothing]]
[(2,1),(4,2),(6,3),(8,4),(10,5)]
Putting the condition in a list and using <-
to extract the result seems ad hoc.
I tried:
> [(i, j) | i <- [1..10],
let Just j = if (even i) then Just (i `div` 2) else Nothing]
But that failed.
The following works but seems awkward:
> [(i, j) | i <- [1..10],
let x = if (even i) then Just (i `div` 2) else Nothing,
isJust x,
let Just j = x]
[(2,1),(4,2),(6,3),(8,4),(10,5)]
Is there a preferred way to do this.
I know this particular problem can be solved in other ways, but let's assume I want to pattern match conditionally in a list comprehension. Is there a good way to do that?
Thanks.
Upvotes: 4
Views: 812
Reputation: 116139
Would this be acceptable for you?
[(i, j) | i <- [1..10], even i, let j = i `div` 2]
Another (IMO worse) option:
[(i, j) | i <- [1..10],
j <- if even i then [i `div` 2] else []]
Yet another:
do i <- [1..10]
j <- guard (even i) >> return (i `div` 2)
return (i,j)
Yet another:
[(i, j) | i <- [1..10],
j <- [i `div` 2 | even i]]
Really overkill and strongly not recommended:
{-# LANGUAGE PatternSynonyms, ViewPatterns #-}
testEvenRight :: Integral a => Either b a -> Maybe a
testEvenRight (Right n) | even n = Just n
testEvenRight _ = Nothing
pattern EvenRight n <- (testEvenRight -> Just n)
list1 = [Right 2, Right 1, Left "abc", Right 4, Right 5]
list2 = [(i,j) | EvenRight i <- list1 , let j = i `div` 2]
Upvotes: 2