Haskell递归Category转路径字符串函数返回空列表及嵌套映射疑问
解决递归Category转路径字符串的问题
首先,你的函数返回空列表的核心原因是缺少叶子节点的基础处理逻辑。让我们一步步拆解问题:
问题根源分析
当处理一个没有子分类的Category(比如Category "C" [])时,printCategories $ sub c会返回[](因为sub c是空列表)。接下来的两次映射:
(" > " ++) <$> [] -- 结果还是[] ((name c)++) <$> [] -- 结果仍然是[]
整个递归链到叶子节点就没有输出了,最终所有层级的拼接都得不到有效字符串,自然返回空列表。
另外,你嵌套的fmap(也就是<$>)逻辑本身是对的——它等价于fmap (\s -> name c ++ " > " ++ s) (printCategories $ sub c),但前提是递归调用能返回非空的路径列表,而基础情况的缺失导致了这个前提不成立。
修正后的实现
我们需要添加叶子节点的处理分支,当分类没有子节点时,直接返回仅包含当前分类名称的列表:
data Category = Category { name :: String , sub :: [Category] } deriving (Show) printCategories :: [Category] -> [String] printCategories = concatMap buildPath where buildPath :: Category -> [String] -- 基础情况:叶子节点,返回自身名称作为单独路径 buildPath (Category name []) = [name] -- 递归情况:将当前名称作为前缀,拼接到所有子路径前 buildPath (Category name subs) = map (\subPath -> name ++ " > " ++ subPath) (printCategories subs)
测试验证
用你给出的例子测试:
testCategory :: Category testCategory = Category "A" [ Category "B" [Category "C" []] , Category "D" [] ] -- 调用 printCategories [testCategory] -- 输出:["A > B > C", "A > D"]
(注:你原问题里写的预期输出是["A > B > C", "A > B > D"],这应该是笔误,因为D是A的直接子分类,不是B的子分类)
额外优化(可选)
如果想让代码更简洁,可以用<>(Data.Monoid里的拼接操作)代替++,或者用foldr来处理拼接,但核心逻辑还是保持基础情况+递归拼接的结构。
内容的提问来源于stack exchange,提问作者Domba
相关产品推荐
相关产品推荐

