I'm trying to solve the MINFREE problem in "Pearls of Functional Algorithm Design" using mutable arrays. The problem is as follows: given a list of n
natural numbers, find the smallest natural number that does not appear in the list. I'm pretty sure that the following is a solution:
minFree2 :: [Int] -> Int
minFree2 ns = (fromMaybe 0 $ elemIndex True seen)
where
bound = (1, length ns)
seen = elems $ runSTArray $ do
arr <- newSTArray bound False
mapM_ (\n -> writeArray arr n False) ns
return arr
But the do
block looks awfully imperative to me, and I'd like to simplify it to a more functional style in order to get a better grasp on monads.
I can get as far as the following (rewriting only the where
clause):
bound = (1, length ns)
setTrues arr = mapM_ (flip (writeArray arr) False) ns
seen = elems $ runSTArray $ newSTArray bound False >>= setTrues
But that doesn't work, because it returns ()
rather than STArray s i e
. I'd like to write something like:
setTrues arr = mapM_ (flip (writeArray arr) False) ns >> arr
the same way I might write fn arr => map ....; arr
in SML, but that doesn't work here because arr
is an STArray s i e
rather than a ST s (STarray s i e)
. I'd expect to be able to fix that by wrapping arr
back up in an ST
, but my attempt with:
setTrues arr = mapM_ (flip (writeArray arr) False) ns >> arr
seen = elems $ runSTArray $ newSTArray bound False >>= return . setTrues
Yields the error:
No instance for (MArray (STArray s) Bool (STArray s Int))
arising from a use of `setTrues'
which I don't entirely understand.
Is there a nice way to write this code, minimizing the use of do
?