Zomil
Zomil

Reputation: 23

Some kind of iteration

Sorry if the title is bad...

So my problem is that i got this code:

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)

my type must be: asd :: [Int]->[Int]->[Int]

I spent my half day figuring out a good solution, but I just cant think on one, so I would be very happy if someone could help me. I want to subtract from the (a:as)list the (b:bs)list and after this I want to delete the first number and do it again with the result(result-(b:bs)), until I get a (length (b:bs))-1) list. And if the (a:as)/result is lower than the (b:bs), for exapmle: 00101<10011 I need to change all (b:bs) numbers to 0(and if the result is higher again keep using the (b:bs)). The exapmle is working fine with the code above, but I want to use it with any list. Maybe I need to use the iterate function but I wasnt able to figure out how.

Here is an example:

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

Thank you so much for your help!

edit: With this I can check which binary number is higher, so with this I can turn all bs number into 0, but i dont know how to implement it.

(%>=%) :: [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

Result:

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]

Upvotes: 0

Views: 136

Answers (1)

dflemstr
dflemstr

Reputation: 26157

It seems like you're trying to implement the remainder rem (similar to modulo mod) function but for binary lists. It is much faster if you convert the list to an Integer and perform rem on it.

First, a function that converts from binary to an Integer:

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

Then, a function that converts an Integer into binary:

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

Finally, a function that handles rem for binary lists:

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

The "beauty" of this solution is that you can replace the 2's with any number (3, 6, 13 etc) and it will work for any base - not just binary.


To answer your original question:

This is a very strange function indeed, and I would not use iterate for it.

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

The last part of asd could also be written like this:

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

That way, it follows your description more closely.

Upvotes: 2

Related Questions