Search code examples
haskellintegermultiplication

Multiplication AbstractInteger


I have a datatype:

data AbstractInteger = Zero
                     | Succ AbstractInteger
                     | Pred AbstractInteger
                     deriving (Show, Eq)

I already have two functions:

1) Convert AbstractInteger into Integer:

aiToInteger :: AbstractInteger -> Integer
aiToInteger (Zero) = 0
aiToInteger (Succ next) = 1 + (aiToInteger next)
aiToInteger (Pred prev) = (aiToInteger prev) - 1

2) Addition AbstractInteger :

plusAbs :: AbstractInteger -> AbstractInteger -> AbstractInteger
plusAbs a b | aiToInteger a == 0 = b
            | aiToInteger b == 0 = a
            | aiToInteger a > 0 = (Succ (plusAbs (Pred a) b))
            | otherwise = (Pred (plusAbs (Succ a) b))

But I don't understand how to create multiply function.

I wrote this but it's not work.

multiplyAbs :: AbstractInteger -> AbstractInteger -> AbstractInteger
multiplyAbs _ (Zero) = (Zero)
multiplyAbs (Zero) _ = (Zero)
multiplyAbs a (Succ Zero) = a
multiplyAbs (Succ Zero)  b = b
multiplyAbs a b = (plusAbs a (timesAbs a (Pred(b))))

Solution

  • As you've implemented aiToInteger, you might want to implement iToAi, something like:

    iToAi :: Integer -> AbstractInteger
    iToAi a | a == 0 = Zero
            | a < 0 = Pred (iToAi (a + 1))
            | a > 0 = Succ (iToAi (a - 1))
    

    Then plusAbs and multiplyAbs will come down to converting abstract integers to integers, perform the operations on them and convert them back:

    plusAbs' :: AbstractInteger -> AbstractInteger -> AbstractInteger
    plusAbs' a b = iToAi (aiToInteger a + aiToInteger b)
    
    multiplyAbs' :: AbstractInteger -> AbstractInteger -> AbstractInteger
    multiplyAbs' a b = iToAi (aiToInteger a * aiToInteger b)
    

    But I'd suggest trying to implement the functions by using pattern-match on the arguments, something like:

    negative :: AbstractInteger -> AbstractInteger
    negative Zero = Zero
    negative (Succ a) = Pred (negative a)
    negative (Pred a) = Succ (negative a)
    
    multiplyAbs :: AbstractInteger -> AbstractInteger -> AbstractInteger
    multiplyAbs Zero a = Zero
    multiplyAbs (Succ a) b = plusAbs (multiplyAbs a b) b
    multiplyAbs (Pred a) b = plusAbs (multiplyAbs a b) (negative b)
    

    The key point is that Succ a can be associated with (a + 1), that's why (Succ a) * b can be associated with a * b + b. According to this logic (Pred a) * b is converted to a * b - b, that's why you need negative function here.

    plusAbs is implemented similarly:

    • (a + 1) + b is the same as 1 + (a + b)
    • (a - 1) + b is the same as (a + b) - 1

    The logic is just like in your example, but you can avoid using aiToInteger by using pattern-match.