计算列表列表中的非空列表

时间:2019-10-09 18:09:31

标签: list haskell

我试图计算具有递归代码的列表列表中非空列表的数量。 我的目标是写一些简单的东西:

prod :: Num a => [a] -> a
prod [] = 1
prod (x:xs) = x * prod xs

我已经有了定义和边缘条件的想法:

nonEmptyCount :: [[a]] -> Int
nonEmptyCount [[]] = 0

我不知道如何继续,有什么提示吗?

3 个答案:

答案 0 :(得分:5)

我认为您的基本情况可以简化。作为基本情况,我们可以采用空列表[],而不是带有空列表的单例列表。对于递归情况,我们可以考虑(x:xs)。在这里,我们需要区分x是一个空列表,而x是一个非空列表。我们可以通过模式匹配或使用警卫来做到这一点:

nonEmptyCount :: [[a]] -> Int
nonEmptyCount [] = 0
nonEmptyCount (x:xs) = -- …

话虽如此,您根本不需要递归。您可以先过滤您的列表,以省略空列表,然后在该列表上调用长度:

nonEmptyCount :: [[a]] -> Int
nonEmptyCount = length . filter (…)

在这里您仍然需要填写

答案 1 :(得分:2)

旧时尚图案匹配应为:

import Data.List

nonEmptyCount :: [[a]] -> Int
nonEmptyCount []     = 0
nonEmptyCount (x:xs) = if null x then 1 + (nonEmptyCount xs) else nonEmptyCount xs 

答案 2 :(得分:1)

以下内容发表在评论中,现已删除:

countNE = sum<$>(1<$)<<<(>>=(1`take`))

这肯定会让未开始的人感到恐惧,但实际上,它等同于

        = sum <$> (1 <$) <<< (>>= (1 `take`))
        = sum <$> (1 <$) . (take 1 =<<)
        = sum . fmap (const 1) . concatMap (take 1)
        = sum . map (const 1) . concat . map (take 1)

进一步等同于

countNE xs  =  sum . map (const 1) . concat $ map (take 1) xs
            =  sum . map (const 1) $ concat [take 1 x | x <- xs]
            =  sum . map (const 1) $ [ r | x <- xs, r <- take 1 x]
            =  sum $ [const 1 r | (y:t) <- xs, r <- take 1 (y:t)]   -- sneakiness!
            =  sum   [const 1 r | (y:_) <- xs, r <- [y]]
            =  sum   [const 1 y | (y:_) <- xs]
            =  sum   [ 1        | (_:_) <- xs]    -- replace each
                         --   non-empty list
                         --             in 
                         --                xs
               -- with 1, and
           --  sum all the 1s up!
            =  (length . (take 1 =<<)) xs
            =  (length . filter (not . null)) xs

这应该更加清晰,即使是有点偷偷摸摸的方式。它本身不是递归的,是的,但是sum都将由给定的Haskell实现递归实现。

此方法将length重新实现为sum . (1 <$),将filter p xs重新实现为[x | x <- xs, p x],并使用等效项not (null xs) === (length xs) >= 1

看到了吗? Haskell很有趣。即使它还没有感觉,但是会的。 :)