Short answer: there are systems that allow what you want. For example, you can do this using the ST monad in Haskell (as noted in the comments).
ST monad approach from Haskell Control.Monad.ST . Code written in the ST monad can use links ( STRef ) where convenient. The nice part is that you can even use the results of the ST monad in clean code, since it is essentially autonomous (this is basically what you wanted in the question).
The proof of this autonomous property is through a type system. The ST monad contains a state-stream parameter, usually denoted by a variable of type s . When you have such a calculation, you will have a monodic result with a type of type:
foo :: ST s Int
To turn this into a net result, you should use
runST :: (forall s . ST sa) -> a
You can read this type, for example: give me a calculation, where a parameter of type s does not matter, and I can return the result of the calculation without ST baggage. This basically keeps the mutable ST variables from escaping, since they will carry s with them, which will depend on the type system.
This can be used for a good effect for clean structures that are implemented with basic mutable structures (for example, a vector package ). You can undo immutability for a limited time to do something that mutates the underlying array. For example, you could combine an immutable Vector with a package of impure algorithms to maximize the performance characteristics of in-place sorting algorithms and still get clean.
In this case, it will look something like this:
pureSort :: Ord a => Vector a -> Vector a pureSort vector = runST $ do mutableVector <- thaw vector sort mutableVector freeze mutableVector
The thaw and freeze functions are linear-time copying, but this will not violate the O (n lg n) total runtime. You can even use unsafeFreeze to avoid another linear traversal, since the mutable vector is no longer used.
ScottWest
source share