show函数递归调用问题:自定义MyList转Haskell风格反转字符串异常
嘿,我来帮你搞定这个自定义MyList的show输出问题!看起来你是想让自己的MyList类型输出类似Haskell原生列表的字符串,但要么输出混乱,要么遇到了递归调用的坑,咱们一步步来解决:
先搞清楚问题根源
你提到调用showList [1,2,3]得到混乱输出,大概率是因为你在实现的时候直接递归拼接了整个子列表的字符串,比如错误写法会把MyList 1 (MyList 2 ...)输出成[1,[2,[3,[]]]]——这是因为递归时把子列表的完整字符串(带括号)直接拼进去了,而不是展开元素。
第一步:先实现正常的原生列表风格输出
先把基础的Show逻辑写对,模拟Haskell原生列表的[元素1,元素2,元素3]格式,我们需要用一个辅助函数来逐个遍历元素,避免嵌套括号:
data MyList a = MyList a (MyList a) | Empty -- 给MyList实现Show实例,输出原生列表风格的字符串 instance Show a => Show (MyList a) where show Empty = "[]" show (MyList head tail) = "[" ++ joinElements (MyList head tail) ++ "]" where -- 辅助函数:把列表元素拼接成"a,b,c"的形式 joinElements Empty = "" joinElements (MyList h Empty) = show h -- 最后一个元素,不加逗号 joinElements (MyList h t) = show h ++ "," ++ joinElements t
现在测试一下:
testList = MyList 1 (MyList 2 (MyList 3 Empty)) main = putStrLn $ show testList -- 会输出 "[1,2,3]",和原生列表一致
第二步:实现反转后的字符串输出
如果你的需求是输出反转后的列表字符串(比如输入[1,2,3]要输出[3,2,1]),那我们先给MyList写个反转函数,再结合上面的Show逻辑:
-- 实现MyList的反转函数 reverseMyList :: MyList a -> MyList a reverseMyList lst = reverseHelper lst Empty where reverseHelper Empty acc = acc reverseHelper (MyList h t) acc = reverseHelper t (MyList h acc) -- 你的showList函数:输出反转后的列表字符串 showList :: Show a => MyList a -> String showList lst = show (reverseMyList lst)
现在调用showList testList就会得到"[3,2,1]",完全符合你的需求!
第三步:避免递归调用的坑
你之前遇到的递归问题,本质是没有区分“元素的字符串”和“整个列表的字符串”:
- 错误的做法:直接把
showList tail的结果拼进去,导致嵌套括号 - 正确的做法:用辅助函数遍历每个元素,只拼接元素的
show值,而不是子列表的完整字符串
比如千万不要写这种错误代码:
-- 错误示例!会输出[1,[2,[3,[]]]] showList (MyList h t) = "[" ++ show h ++ "," ++ showList t ++ "]"
这种写法会把每个子列表的完整字符串(带[])都拼进去,自然就混乱了。
内容的提问来源于stack exchange,提问作者JamalCrawford..
相关产品推荐
相关产品推荐

