Aleksandar Topuzović
Given an 2D array representing a spreadsheet calculate the checksum of the spreadsheet. The checksum is calculated by summing up the checksum of each row. Row checksum is the difference between the largest and the smallest number.
5 1 9 5
7 5 3
2 4 6 8
We calculate the checksum
First row: 9 - 1 = 8
Second row: 7 - 3 = 4
Third row: 8 - 2 = 6
Checksum = 8 + 4 + 6 = 18
We implement our own min max finder using a fold
findMinMax (x:xs) = foldr helper (x, x) xs
where
helper x (cmin, cmax) =
let nmin = if x < cmin then x else cmin
nmax = if x > cmax then x else cmax in
(nmin, nmax)
rowCksum :: (Num a, Ord a) => [a] -> a
rowCksum xs = rmax - rmin
where
(rmin, rmax) = findMinMax xs
cksum :: (Num a, Ord a) => [[a]] -> a
cksum = sum . map rowCksum
In mathematics, a semigroup is an algebraic structure consisting of a set together with an associative binary operation.
Laws
(A ⊕ B) ⊕ C = A ⊕ (B ⊕ C)
Implemented as a typeclass
Laws
https://hackage.haskell.org/package/base/docs/Data-Semigroup.html
It is a semigroup with an identity element
Laws
A ⊕ E = E ⊕ A = A
(A ⊕ B) ⊕ C = A ⊕ (B ⊕ C)
Laws
https://hackage.haskell.org/package/base/docs/Data-Monoid.html
Num monoids
Bool monoids
We can reuse Min
, Max
and
Sum
instance Ord a => Semigroup (MinMax a) where
a <> b = MinMax (myMin a <> myMin b) (myMax a <> myMax b)
We iterate trough the row only once and combine the elements of the row by using the custom monoid.
For the row checksum we use the Sum monoid which we combine with other rows to obtain the spreadsheet checksum.
We wrap our semigroup in a Maybe to obtain a monoid.
It makes the handling of empty rows/spreadsheets trivial.
calcDiff :: (Applicative f, Num a) => (f a, f a) -> f a
calcDiff x = (-) <$> (snd x) <*> (fst x)
rowCksum :: (Num a, Ord a) => [a] -> Maybe (Sum a)
rowCksum xs = fmap Sum $ calcDiff res'
where
res' = bimap (fmap getMin) (fmap getMax) res
res = foldMap mkMinMax xs
cksum :: (Num a, Ord a) => [[a]] -> Maybe a
cksum xs = fmap getSum $ foldMap (rowCksum) xs
github.com/atopuzov
twitter.com/atopuzov