某种迭代

时间:2012-05-05 23:19:32

标签: haskell iteration

很抱歉,如果标题不好......

所以我的问题是我得到了这段代码:

asd (a:as) (b:bs)= tail(rox(tail(rox (tail (rox (a:as) (b:bs))) (b:bs))) (b:bs))
rox [] as = as
rox as [] = as
rox (a:as) (b:bs) = map abs (a-b:rox as bs)

我的类型必须是:asd :: [Int]->[Int]->[Int]

我花了半天时间找出一个好的解决方案,但我只能想到一个,所以如果有人能帮助我,我会很高兴。 我想从(a:as)列表中减去(b:bs)列表,之后我想删除第一个数字并再次使用结果(结果 - (b:bs)),直到我得到一个(长度(b:bs)) - 1)列表。如果(a:as)/结果低于(b:bs),则exapmle:00101< 10011我需要将所有(b:bs)数字更改为0(如果结果更高,则继续使用(b:BS))。使用上面的代码,exapmle工作正常,但我想在任何列表中使用它。也许我需要使用迭代函数,但我无法弄清楚如何。

以下是一个例子:

11010(a:as)
101(b:bs)
01110(result)
 1110(after using tail)
 101(b:bs again)
 0100(result)
  100(after tail)
  101(b:bs)
  001(result)
   01(final result after using tail, so its 1number shorter than the (b:bs) list

非常感谢你的帮助!

编辑: 有了这个,我可以检查哪个二进制数更高,所以我可以将所有的bs数转换为0,但我不知道如何实现它。

(%>=%) :: [Int] -> [Int] -> Bool
(%>=%) [] [] = True
(%>=%) as [] = True
(%>=%) [] bs = False
(%>=%) as bs
    | filter (/=0) (takeWhile (>(-1))(ro as bs))==[]=False
    | elem 1 (takeWhile (>(-1))(ro as bs))==True=True

ro :: [Int] -> [Int] -> [Int]
ro []       bs       = bs
ro as       []       = as
ro (a:as) (b:bs) = (2*a) - b: ro as bs

结果:

asd [1,1,1,0,0,1,0,1,0,0,0,0] [1,1,0,1,1]
asd [0,1,1,1,1,0,1,0,0,0,0] [1,1,0,1,1]
asd [1,1,1,1,0,1,0,0,0,0] [1,1,0,1,1]
asd [0,1,0,1,1,0,0,0,0] [1,1,0,1,1]
asd [1,0,1,1,0,0,0,0] [1,1,0,1,1]
asd [0,1,1,0,0,0,0] [1,1,0,1,1] < here is something wrong because its: 1,1,0,1,0,0,0 and from here everything is wrong
asd [1,1,0,0,0,0] [1,1,0,1,1]
asd [1,0,0,0,0] [1,1,0,1,1]
asd [0,0,0,0] [1,1,0,1,1]
[0,0,0,0]

1 个答案:

答案 0 :(得分:2)

您似乎正在尝试实现余数rem(类似于模mod)函数,但用于二进制列表。如果您将列表转换为Integer并对其执行rem,速度会快得多。

首先,一个从二进制转换为Integer的函数:

unbinary :: [Int] -> Integer
unbinary = foldl (\ a b -> a * 2 + fromIntegral b) 0

然后,将Integer转换为二进制的函数:

binary :: Integer -> [Int]
binary = reverse . go
  where
    go 0 = []
    go d =
      let (q, r) = quotRem d 2
      in fromIntegral r : binary q

最后,为二进制列表处理rem的函数:

remBinary :: [Int] -> [Int] -> [Int]
remBinary a b = binary $ inta `rem` intb
  where
    inta = unbinary a
    intb = unbinary b

这个解决方案的“美感”是你可以用任何数字(3,6,13等)代替2,它可以用于任何基础 - 而不仅仅是二进制。


回答你原来的问题:

这确实是一个非常奇怪的功能,我会使用iterate

asd :: [Int] -> [Int] -> [Int]
-- If there is nothing to subtract, let's assume that we should return as
asd as [] = as
asd as bs
  -- If the length of `as` is shorter than `bs`, we are done.
  | length as < length bs
  = as
  | head as == 0
  = asd (tail as) bs
  -- Otherwise, compute `rox as bs`, take its `tail`, and call `asd` recursively
  | otherwise
  = asd (tail (rox as bs)) bs

-- I simplified your version of this function a bit
rox :: [Int] -> [Int] -> [Int]
rox []       bs       = bs
rox as       []       = as
rox (a : as) (b : bs) = abs (a - b) : rox as bs

asd的最后一部分也可以这样写:

  = let diff = rox as bs
        tailOfDiff = tail diff
    in asd tailOfDiff bs

这样,它会更贴切地跟随您的描述。