You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 08:48:28