DEV Community

Discussion on: Daily Challenge #287 - 16+18=214

Collapse
 
cipharius profile image
Valts Liepiņš • Edited

EDIT:
I quite liked purely arithmetic solutions by @willsmart and @qm3ster , so I reimplemented same idea in Haskell:

import Numeric.Natural (Natural)

(^+^) :: Natural -> Natural -> Natural
(^+^) = reducer 1
  where
    reducer c 0 0 = 0
    reducer c a b =
      let sum = a `mod` 10 + b `mod` 10
          delta = if sum < 10 then 10 else 100
      in c * sum + reducer (c * delta) (shift a) (shift b)
    shift x = floor $ fromIntegral x / 10

Solution in Haskell:

import Numeric.Natural (Natural)
import Data.Char (digitToInt)

(^+^) :: Natural -> Natural -> Natural
(^+^) n1 n2 = read $ sumHead n1' n2' <> sumTail n1' n2'
  where
    sumHead x y = maybe "" reverse $ zipRemain x y
    sumTail x y = concat . reverse . fmap (show . add) $ zip x y
    add (x,y) = digitToInt x + digitToInt y
    n1' = reverse $ show n1
    n2' = reverse $ show n2

zipRemain :: [a] -> [a] -> Maybe [a]
zipRemain [] [] = Nothing
zipRemain xs [] = Just xs
zipRemain [] ys = Just ys
zipRemain (_:xs) (_:ys) = zipRemain xs ys

Essentially zips up digit by digit in reverse order, sums and concats the result. zipRemain utility function helps retrieving leftover part of the longer of two zipped lists.

Example for the zipping problem:

a = ["1", "2", "3", "4", "5"]
b = ["a", "b", "c"]
zipAB = zip a b -- [("1","a"), ("2","b"), ("3","c")] 
zipRemainAB = zipRemain a b -- ["4", "5"]