You have 2 options:
Use
freeze
. This requires copying arrays, but you don't need to use any unsafe functions:baz :: (UArray Int Int, UArray Int Bool) baz = runST $ do AP ints bools <- newAP 12 liftM2 (,) (freeze ints) (freeze bools)
Create your variant of
runSTUArray
for two arrays usingunsafeFreezeSTUArray
, knowing that the implementation is actually safe (because there will be no reference to the original mutable arrays left).runSTUArray2 :: (Ix i1, Ix i2) => (forall s . (ST s (STUArray s i1 e1, STUArray s i2 e2))) -> (UArray i1 e1, UArray i2 e2) runSTUArray2 st = runST $ do (a1, a2) <- st liftM2 (,) (unsafeFreezeSTUArray a1) (unsafeFreezeSTUArray a2) baz' :: (UArray Int Int, UArray Int Bool) baz' = runSTUArray2 $ do AP ints bools <- newAP 12 return (ints, bools)
(Perhaps this approach could be even somehow generalized using Generics to allow to return any data structure containing
ST
arrays.)