我试图计算具有递归代码的列表列表中非空列表的数量。 我的目标是写一些简单的东西:
prod :: Num a => [a] -> a
prod [] = 1
prod (x:xs) = x * prod xs
我已经有了定义和边缘条件的想法:
nonEmptyCount :: [[a]] -> Int
nonEmptyCount [[]] = 0
我不知道如何继续,有什么提示吗?
答案 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
和list-comprehension都将由给定的Haskell实现递归实现。
此方法将length
重新实现为sum . (1 <$)
,将filter p xs
重新实现为[x | x <- xs, p x]
,并使用等效项not (null xs) === (length xs) >= 1
。
看到了吗? Haskell很有趣。即使它还没有感觉,但是会的。 :)