0

I'm trying to build a recursive function, which for simplicity's sake, lets say it takes an list and builds an array and a list. Because I need to both read and write the array as it's being built, I'm using a mutable array so I can do constant time reads and writes. So the signature and function looks something like as follows:

f :: [a] -> ST s ([a], STArray s Int a) -> ST s ([a], STArray s Int a)
f (x:xs) curr_arr = 
  case blah of
    ... -> f xs new_arr
f [] curr_arr = curr_arr

I want a function h with the following signature:

h :: Int -> Int -> a -> [a] -> (Array Int a, [a])

And I want it to have the roughly following implementation:

h lbound ubound default_a xs = g (f xs (newArray lbound ubound default_a))

Problem is, I need a function g with this signature:

ST s ([a], STArray s Int a) -> (Array Int a, [a])

but I can't seem to hack together runST and runSTArray to achieve this.

Is there anyway to implement g, or should I make the signature of f completely different in the first place?

Cactus
  • 27,075
  • 9
  • 69
  • 149
Clinton
  • 22,361
  • 15
  • 67
  • 163

1 Answers1

0

You should use the Monad instance of ST s to implement the recursive calls to f (and the composition of their results): change f's type to

f :: [a] -> ([a], STArray s Int a) -> ST s ([a], STArray s Int a)

which means the recursive calls in f will look something like

f xs curr = do
    xs' <- ...
    curr' <- ...
    next <- f xs' curr'
    combine curr next

and then runST it to completion in h (runSTArray doesn't work directly here, because you also have your [a] on the side):

h lo hi x0 xs = runST $ do
    curr <- newArray lo hi x0
    (ys, mArr) <- f xs (xs, curr)
    arr <- freeze mArr
    return (ys, arr)

This works because in that last expression, ys :: [a] and arr :: Array Int a, so neither depends on the choice of s.

Cactus
  • 27,075
  • 9
  • 69
  • 149