列表理解的Monadic方式

时间:2014-03-13 19:05:35

标签: list haskell recursion monads

我有以下功能

combinations :: [[a]] -> [[a]]
combinations []       = [[]]
combinations (xs:xss) = concat [map (x:) yss | x <- xs]
  where yss = combinations xss

产生其元素之间的所有组合:

*Main> combinations [[1,2],[2,3,4],[5,6]]
[[1,2,5],[1,2,6],[1,3,5],[1,3,6],[1,4,5],[1,4,6],[2,2,5],[2,2,6],[2,3,5],[2,3,6]
,[2,4,5],[2,4,6]]

我觉得必须有一种monadic方式来做到这一点

foobar = do
    n <- [1,2]
    ch <- [3,4,5]
    return[n,ch]

这是我走了多远。但我被卡住了。

2 个答案:

答案 0 :(得分:3)

列表monad的功能为sequence

> :t sequence
sequence :: Monad m => [m a] -> m [a]
> sequence [[1,2],[2,3,4],[5,6]]
[[1,2,5],[1,2,6],[1,3,5],[1,3,6],[1,4,5],[1,4,6],[2,2,5],[2,2,6],[2,3,5],[2,3,6],
[2,4,5],[2,4,6]]

答案 1 :(得分:1)

我能想出的最好的是

combinations [] = [[]]
combinations (xs:xss) = do
    x <- xs
    ys <- combinations xss
    return $ x : ys

我得出这个的方式是我首先将列表理解转换为monadic代码(这也意味着删除concat以使其进行类型检查)

combinations (xs:xss) =
    let yss = combinations xss
    in do
        x <- xs
        map (x:) yss

然后我意识到map (x:) yss正是fmap (x:) yss,这正是yss >>= return . (x:),所以我知道我可以做到

combinations (xs:xss) =
    let yss = combinations xss
    in do
        x <- xs
        ys <- yss
        return $ x : ys

然后它可以内联为

combinations (xs:xss) = do
    x <- xs
    ys <- combinations xss
    return $ x : ys