Haskell函数精简咨询:如何优化swap辅助函数与move函数的冗余代码
精简你的Haskell代码:从重复到通用
首先解决你最头疼的move函数重复代码问题,然后再优化swap函数的冗余逻辑。
一、彻底精简move函数
你的move函数重复代码的核心原因是每个分支都在执行相同的流程:取出两个列表→调用swap→替换回原位置。我们可以把这个逻辑抽象成通用步骤,完全消除重复分支:
move :: Int -> Int -> [[Int]] -> [[Int]] move a b ints | a == b = error "a and b cannot be the same integer" | not (a `elem` [1,2,3] && b `elem` [1,2,3]) = error "a and b must be either 1, 2 or 3" | otherwise = let sIdx = a - 1 dIdx = b - 1 sList = ints !! sIdx dList = ints !! dIdx [newS, newD] = swap sList dList -- 辅助函数:替换列表指定索引的元素 replaceAt :: Int -> a -> [a] -> [a] replaceAt idx val xs = let (before, after) = splitAt idx xs in before ++ val : tail after in replaceAt dIdx newD $ replaceAt sIdx newS ints
关键优化点:
- 用
replaceAt辅助函数统一处理列表元素替换,避免每个分支手动拼接列表 - 提取源/目标索引的通用计算,消除分支中的重复索引转换
- 把所有错误判断集中在开头,核心逻辑只保留通用流程
如果想进一步提升安全性(避免!!的索引越界风险),可以用模式匹配处理固定长度的输入:
move :: Int -> Int -> [[Int]] -> Maybe [[Int]] move a b [x,y,z] | a == b = Nothing | not (a `elem` [1,2,3] && b `elem` [1,2,3]) = Nothing | otherwise = Just $ case (a,b) of (1,2) -> let [nx, ny] = swap x y in [nx, ny, z] (1,3) -> let [nx, nz] = swap x z in [nx, y, nz] (2,1) -> let [ny, nx] = swap y x in [nx, ny, z] (2,3) -> let [ny, nz] = swap y z in [x, ny, nz] (3,1) -> let [nz, nx] = swap z x in [nx, y, nz] (3,2) -> let [nz, ny] = swap z y in [x, ny, nz] move _ _ _ = Nothing -- 处理非3元素列表的非法输入
这个版本用Maybe替代error,避免运行时崩溃,同时代码量仍远少于你原来的实现。
二、优化swap函数的冗余逻辑
你的swap函数存在重复计算和不必要的分支,利用“列表固定为5个元素”的约束可以大幅简化:
swap :: [Int] -> [Int] -> [[Int]] swap xs ys | xs == ys = [xs, ys] | all (==0) xs = [xs, ys] -- 源列表全零,无法移动元素,避免崩溃 | otherwise = let nonZeroX = filter (/=0) xs e = head nonZeroX remainingX = tail nonZeroX -- 构建新的源列表:剩余非零元素补0到5个 newX = remainingX ++ replicate (5 - length remainingX) 0 -- 构建新的目标列表:原非零元素+e,补0到5个(和你原逻辑一致) -- 如果需要把e放到ys末尾,直接用 newY = take 4 ys ++ [e] nonZeroY = filter (/=0) ys newNonZeroY = nonZeroY ++ [e] newY = newNonZeroY ++ replicate (5 - length newNonZeroY) 0 in [newX, newY]
关键优化点:
- 增加源列表全零的判断,避免
head $ filter (/=0) xs的崩溃风险 - 只计算一次
nonZeroX和nonZeroY,消除重复的过滤计算 - 利用固定长度5简化补0逻辑,代码更清晰易读
- 统一了ys全零和非全零的处理逻辑,去掉了冗余分支
内容的提问来源于stack exchange,提问作者Mampenda
相关产品推荐
相关产品推荐

