I have been learning Haskell for the past month or two, and recently solved this coding problem. The additional challenge was to do the task without extra space and in linear time, which I did not think would be possible to do in a purely functional way, so naturally I found out about the ST monad and I thought this would be a good opportunity to learn more about it. Anyways, here is the code that I wrote:
module FindDuplicates where
import Control.Monad (foldM)
import Control.Monad.ST
import Data.Array.ST
xs = [4,3,2,7,8,2,3,1] :: [Int]
findDuplicates :: [Int] -> ST s [Int]
findDuplicates xs = do
arr <- newListArray (1, length xs) xs :: ST s (STArray s Int Int)
let go :: [Int] -> Int -> ST s [Int]
go acc i = do x <- abs <$> readArray arr i
y <- readArray arr x
if y < 0
then return (x:acc)
else do writeArray arr x (-y)
return acc
foldM go [] [1..length xs]
The idea is to use the pre-condition that 1 ≤ a[i] ≤ n and that each element appears at most 2 times. But the code gives me the following error.
FindDuplicates.hs:14:36:
No instance for (MArray (STArray s) Int (ST s1))
arising from a use of ‘readArray’
In the second argument of ‘(<$>)’, namely ‘readArray arr i’
In a stmt of a 'do' block: x <- abs <$> readArray arr i
In the expression:
do { x <- abs <$> readArray arr i;
y <- readArray arr x;
if y < 0 then
return (x : acc)
else
do { writeArray arr x (- y);
.... } }
I hope someone can point me in the right direction!