jam
jam

Reputation: 823

In Haskell, how to make read-only parameters that depend on ST

Context: When considering the signature of a function in a typical imperative language, some parameters might be denoted as mutable references, some parameters might be denoted as immutable references, some parameters might be seen as simple pure constants.

I am trying to understand how to reproduce this in Haskell, most importantly the mutable/immutable handling of variables that depend on the state.

There are several approaches to manage state in Haskell. One approach seems to be via State/StateT/MonadState which fit well with monad transformers. Among stateful function parameters, if I want to make it explicit that one should be regarded as immutable inside the function body, I believe answers to that question: Making Read-Only functions for a State in Haskell explain well how to do it, by using Reader or MonadReader.

Another approach to manage state (which I am more interested in that case), is with ST. I like ST better because, it allows to manage more than just one memory cell at the same time, and it appears to be more performant than State. The problem now is that I don't know how to properly manage a distinction between mutable/immutable stateful variables in ST. The Reader way does not seem to apply in that case. I have been looking at the STMonadTrans package which seems to help make ST fit with monad transformers, but I am not sure how to use it.

Question: Do you have a simple example of a function f that creates a mutable variable x with newSTRef, and passes x to a function g, in an immutable way, that is, in such a way that g can read x but not modify x? If not is there a workaround?

Remark 1: A workaround could be to freeze the mutable variables before passing them to make them pure, however in my case its not acceptable solution because freezing can be either expensive or unsafe, and it is not possible to freeze complex structures quickly such as vectors of vectors. Unsafe coerce is not acceptable either. I am looking for a safe zero runtime cost solution.

Remark 2: Someone said I can just read the reference before going into the function, but this is over simplified answer to my simplified question. In a more general context, it is possible that one cannot readSTRef the variable x before going into the function g because x is more complex like a set of mutable arrays. I am still asking my question in that simple way to try to figure out how to do the general thing on a simple example.

Thanks

Upvotes: 2

Views: 202

Answers (1)

luqui
luqui

Reputation: 60463

I haven't read the novel that is the comments section, but a pattern like

newtype ReadOnly s a = ReadOnly (ST s a)

makeReadOnly :: STRef s a -> ReadOnly s a
makeReadOnly = ReadOnly . readSTRef

has served me well. This is a classic trick: if you want a data type to support some operations, just define the data type to be a record of the operations you want to support. In this case, there is only one.

(As a bonus, it can be seen from this that "read only variables" are highly composable!)

Upvotes: 1

Related Questions