【问题标题】:Simplify function for HaskellHaskell 的简化函数
【发布时间】:2021-10-30 04:34:35
【问题描述】:

我有这段代码,在我看来太长了。我想知道是否有办法简化或缩短它。

我有这个辅助函数swap,它接收两个整数列表,并在将一个数字从一个交换到另一个后返回它们所有列表中有5个整数,所以如果小于,我用零填充那个。

看起来像这样:

-- Takes in two lists and moves one non-zero int from one to the other
swap :: [Int] -> [Int] -> [[Int]]
swap xs ys
  | xs == ys = [xs, ys]                                             -- If both lists are all zeroes
  | all (==0) ys =                                                  -- If the second list is all zeroes
    let
        e = head $ filter (/= 0) xs                                 -- First non-zero element from first list
        newX = replicate (length xs - length (filter (/= 0) xs) - 1) 0 ++ tail (filter (/= 0) xs)
        newY = tail ys ++ [e]
        in
            [newX, newY]
    | otherwise =
    let
        e = head $ filter (/= 0) xs                                 -- First non-zero element from first list
        newX = replicate (length xs - length (filter (/= 0) xs) + 1) 0 ++ tail (filter (/= 0) xs)
        newY = replicate (length (filter (==0) ys) - 1) 0 ++ [e] ++ drop (length xs - length (filter (/= 0) ys)) ys
        in
            [newX, newY]

我在下面的函数中使用它,就是我觉得这个函数太长了:

move :: Int -> Int -> [[Int]] -> [[Int]]
move a b ints
  | a == b = error "a and b cannot be the same integer"
  | a == 1 && b == 2 =
    let
        fst = ints !! (a-1)
        snd = ints !! (b-1)
        swapped = swap fst snd
        in
            [head swapped, last swapped, last ints]
  | a == 1 && b == 3 =
    let
        fst = ints !! (a-1)
        snd = ints !! (b-1)
        swapped = swap fst snd
        in
            [head swapped, ints !! 1, last swapped]
  | a == 2 && b == 1 =
    let
        fst = ints !! (a-1)
        snd = ints !! (b-1)
        swapped = swap fst snd
        in
            [last swapped, head swapped, last ints]
  | a == 2 && b == 3 =
    let
        fst = ints !! (a-1)
        snd = ints !! (b-1)
        swapped = swap fst snd
        in
            [head ints, head swapped, last swapped]
  | a == 3 && b == 1 =
    let
        fst = ints !! (a-1)
        snd = ints !! (b-1)
        swapped = swap fst snd
        in
            [last swapped, ints !! 1, head swapped]
  | a == 3 && b == 2 =
    let
        fst = ints !! (a-1)
        snd = ints !! (b-1)
        swapped = swap fst snd
        in
            [head ints, last swapped, head swapped]
  | otherwise = error "a and b must be either 1, 2 or 3"

此函数接受两个整数和一个由 3 个整数列表组成的列表,其中每个列表有 5 个整数,因此示例输入为 f.ex

[[1,2,3,4,5],[0,0,0,0,0],[0,0,0,0,0]] or 
[[0,0,0,4,5],[0,0,0,2,3],[0,0,0,0,1]] or 
[[0,0,3,4,5],[0,0,0,0,1],[0,0,0,0,2]] 

所以 $a$ 和 $b$ 只能是 1,2 或 3。给我 $2^3=6$ 不同的情况来考虑。即使设法将其归结为 $a>b$ 和 $b>a$ 两种情况,与我期望的适用于 Haskell 的代码行相比,我仍然会得到太多的代码行。有什么办法可以缩短这段代码?

【问题讨论】:

  • 在第一个代码块中,最后一个守卫是不是缩进太多了?
  • 是的,这是我的一个错误,我没有正确缩进,但它应该像其他守卫一样缩进。
  • 我会在今天晚些时候或周日发布。我看到了很多简化的机会。
  • 非常感谢!

标签: haskell


【解决方案1】:

这还不是一个完整的答案,而是一个开始。看看我是如何将所有重复代码删除到 where 块中的。还有很多简化的机会。

-- Takes in two lists and moves one non-zero int from one to the other
swap :: [Int] -> [Int] -> [[Int]]
swap xs ys
    | xs == ys = [xs, ys]                                             -- If both lists are all zeroes
    | all (==0) ys =                                                  -- If the second list is all zeroes
      let
        newX = replicate (length xs - length nonZeroXs - 1) 0 ++ tail nonZeroXs
        newY = tail ys ++ [e]
      in
        [newX, newY]
    | otherwise =
      let
        newX = replicate (length xs - length nonZeroXs + 1) 0 ++ tail nonZeroXs
        newY = replicate (length (filter (==0) ys) - 1) 0 ++ [e] ++ drop (length xs - length (filter (/= 0) ys)) ys
      in
        [newX, newY]
  where
    nonZeroXs = filter (/= 0) xs
    e = head $ filter (/= 0) xs                                 -- First non-zero element from first list

newXs 之间的唯一区别是最后添加的信号。这表明整个决策块可能不在最佳位置。

move :: Int -> Int -> [[Int]] -> [[Int]]
move a b ints
    | a == b = error "a and b cannot be the same integer"
    | a == 1 && b == 2 = [head swapped, last swapped, last ints]
    | a == 1 && b == 3 = [head swapped, ints !! 1,    last swapped]
    | a == 2 && b == 1 = [last swapped, head swapped, last ints]
    | a == 2 && b == 3 = [head ints,    head swapped, last swapped]
    | a == 3 && b == 1 = [last swapped, ints !! 1,    head swapped]
    | a == 3 && b == 2 = [head ints,    last swapped, head swapped]
    | otherwise = error "a and b must be either 1, 2 or 3"
  where 
    fst = ints !! (a-1)
    snd = ints !! (b-1)
    swapped = swap fst snd

仔细查看上面的内容并运行一些测试。我现在没有时间自己测试。

【讨论】:

  • 这非常有用!谢谢你。我现在去看看。
  • @pedrofurla 是否可以通过使用案例来做到这一点?如果是这样,你会怎么做?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-09-30
  • 1970-01-01
  • 2011-10-19
  • 1970-01-01
  • 2015-05-27
相关资源
最近更新 更多