如何在Haskell中的列表理解中有条件地匹配模式

时间:2016-11-14 13:47:44

标签: haskell list-comprehension monads

我想写这样的东西:

> [(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)]

将条件放入列表并使用<-提取结果似乎是 ad hoc

我试过了:

> [(i, j) | i <- [1..10], 
            let Just j = if (even i) then Just (i `div` 2) else Nothing]

但那失败了。

以下作品但似乎很尴尬:

> [(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)]

有没有首选方法可以做到这一点。

我知道这个特殊问题可以通过其他方式解决,但我们假设我想在列表理解中有条件地模式匹配。 有没有好办法呢?

感谢。

1 个答案:

答案 0 :(得分:2)

这对你来说是否可以接受?

[(i, j) | i <- [1..10], even i, let j = i `div` 2]

另一个(IMO更糟)选项:

[(i, j) | i <- [1..10], 
          j <- if even i then [i `div` 2] else []]

又一个:

do i <- [1..10]
   j <- guard (even i) >> return (i `div` 2)
   return (i,j)

又一个:

[(i, j) | i <- [1..10], 
          j <- [i `div` 2 | even i]]

真的有点过分,强烈不推荐:

{-# 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]