Mutable List builder in the ST Monad
1-- | Traversing IO lists.
2--
3-- Code from this module is derived from [Twan van Laarhoven](https://www.twanvl.nl/blog/haskell/unsafe-sequence).
4--
5-- These operations are tail recursive, while building lists by appending
6-- to its tail mutably.
7module Data.Traversable.IO (
8 sequenceIO
9 , traverseIO
10 , unfoldIO
11) where
12
13import Data.ListBuilder.Unsafe
14
15import Prelude hiding (length)
16
17
18-- | Traverse implemented in terms of unsafeSetField.
19--
20-- This operation is tail recursive.
21traverseIO :: (a -> IO b) -> [a] -> IO [b]
22traverseIO _ [] =
23 return []
24traverseIO f (mx0:xs0) = do
25 x0 <- f mx0
26 let front = [x0]
27 go front xs0
28 return front
29 where
30 go _ [] = return ()
31 go back (mx:xs) = do
32 x <- f mx
33 let back' = [x]
34 unsafeSetField 1 back back'
35 go back' xs
36{-# INLINEABLE traverseIO #-}
37
38
39-- | Sequence implemented in terms of unsafeSetField
40--
41-- This operation is tail recursive.
42sequenceIO :: [IO a] -> IO [a]
43sequenceIO =
44 traverseIO id
45{-# INLINE sequenceIO #-}
46
47
48-- | Unfold a list from an IO action returning a 'Maybe' value.
49-- As long as the function returns `Just`, its value will
50-- be appended to the list.
51unfoldIO :: IO (Maybe a) -> IO [a]
52unfoldIO p = do
53 x <- p
54 case x of
55 Nothing ->
56 return []
57 Just a -> do
58 let front = [a]
59 go front
60 return front
61 where
62 go back = do
63 x <- p
64 case x of
65 Nothing -> return ()
66 Just a -> do
67 let back' = [a]
68 unsafeSetField 1 back back'
69 go back'
70{-# INLINEABLE unfoldIO #-}