-- | Traversing IO lists. -- -- Code from this module is derived from [Twan van Laarhoven](https://www.twanvl.nl/blog/haskell/unsafe-sequence). -- -- These operations are tail recursive, while building lists by appending -- to its tail mutably. module Data.Traversable.IO ( sequenceIO , traverseIO , unfoldIO ) where import Data.ListBuilder.Unsafe import Prelude hiding (length) -- | Traverse implemented in terms of unsafeSetField. -- -- This operation is tail recursive. traverseIO :: (a -> IO b) -> [a] -> IO [b] traverseIO _ [] = return [] traverseIO f (mx0:xs0) = do x0 <- f mx0 let front = [x0] go front xs0 return front where go _ [] = return () go back (mx:xs) = do x <- f mx let back' = [x] unsafeSetField 1 back back' go back' xs {-# INLINEABLE traverseIO #-} -- | Sequence implemented in terms of unsafeSetField -- -- This operation is tail recursive. sequenceIO :: [IO a] -> IO [a] sequenceIO = traverseIO id {-# INLINE sequenceIO #-} -- | Unfold a list from an IO action returning a 'Maybe' value. -- As long as the function returns `Just`, its value will -- be appended to the list. unfoldIO :: IO (Maybe a) -> IO [a] unfoldIO p = do x <- p case x of Nothing -> return [] Just a -> do let front = [a] go front return front where go back = do x <- p case x of Nothing -> return () Just a -> do let back' = [a] unsafeSetField 1 back back' go back' {-# INLINEABLE unfoldIO #-}