Haskell中if语句多行代码编写问题及递归函数编译错误修复
修复Haskell递归函数
doubleEveryOther的编译错误 错误原因分析
你的代码存在两个核心问题:
- 函数调用参数错误:
doubleEveryOther init (init x)是完全错误的调用方式。doubleEveryOther的类型是[Integer] -> [Integer],仅接受一个列表参数,但你传入了两个参数——init是一个函数(类型为[a] -> [a])而非列表,这直接导致类型不匹配,编译器提示"init参数不足"也是因为你把init当成了doubleEveryOther的参数,而非用来处理列表的函数。 - 表达式拆分错误:你把递归结果和最终的两个元素分成了两行,Haskell要求
else分支必须是一个单一表达式,拆分后的两行会被视为独立语句,无法合并成正确的返回值。
修复后的代码
基础修复版本
直接修正参数错误并拼接列表:
doubleEveryOther :: [Integer] -> [Integer] -- 将输入列表中从右数第2个元素翻倍 doubleEveryOther [] = [] doubleEveryOther x = if length x < 2 then x else doubleEveryOther (init (init x)) ++ [2 * last (init x), last x]
优化版本(避免重复计算)
通过变量绑定减少重复调用init和last,提升可读性:
doubleEveryOther :: [Integer] -> [Integer] doubleEveryOther [] = [] doubleEveryOther x | length x < 2 = x | otherwise = let trimmed = init (init x) secondLast = last (init x) lastElem = last x in doubleEveryOther trimmed ++ [2 * secondLast, lastElem]
更优雅的模式匹配版本
用模式匹配替代length、init、last,逻辑更直观:
doubleEveryOther :: [Integer] -> [Integer] doubleEveryOther [] = [] doubleEveryOther [single] = [single] doubleEveryOther (xs ++ [secondLast, lastElem]) = doubleEveryOther xs ++ [2 * secondLast, lastElem]
修复说明
- 递归调用时,需要传入去掉最后两个元素的列表:
init (init x)会先移除列表最后一个元素,再移除新列表的最后一个元素,得到除最后两个元素外的部分。 - 用列表拼接运算符
++将递归处理后的列表,与"翻倍后的倒数第二个元素+最后一个元素"的新列表合并,作为最终返回值。
内容的提问来源于stack exchange,提问作者FllamingBarfi YT
相关产品推荐
相关产品推荐

