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

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

关键优化点:

  1. 用replaceAt辅助函数统一处理列表元素替换,避免每个分支手动拼接列表
  2. 提取源/目标索引的通用计算,消除分支中的重复索引转换
  3. 把所有错误判断集中在开头,核心逻辑只保留通用流程

如果想进一步提升安全性(避免!!的索引越界风险),可以用模式匹配处理固定长度的输入:

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]

关键优化点:

  1. 增加源列表全零的判断,避免head $ filter (/=0) xs的崩溃风险
  2. 只计算一次nonZeroX和nonZeroY,消除重复的过滤计算
  3. 利用固定长度5简化补0逻辑,代码更清晰易读
  4. 统一了ys全零和非全零的处理逻辑,去掉了冗余分支

内容的提问来源于stack exchange,提问作者Mampenda

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 22:58:12