[darcs-users] repository IO and type witnesses

Ganesh Sittampalam ganesh at earth.li
Sat Aug 30 01:30:42 UTC 2008


Hi David,

As Jason mentioned, I've been trying to help Jason sort out some of the 
repository type witness stuff. I've been getting rather confused by the 
discussions you've been having, perhaps I only have a high level view of 
things. However I'm not convinced that the types you are proposing make 
complete sense, so I'd like to propose an alternative, and thus clear up my 
confusion one way or another.

As I understand it, the current plan is to have

newtype RIO p C(r u t t') a = UnsafeRIO (Repository p C(r u t) -> IO a)

The idea being that an action of type RIO p C(r u t t') a operates on a 
repository that contains patches of type p, and that is in recorded state r, 
unrecorded state u, and tentative state t, and returns one in tentative state 
t' (other states unchanged).

With this type, RIO covers all the tentative operations. For other operations, 
the changing states are handled by a changing Repository, for example your 
proposed withGuts:

> withGutsOf :: Repository p C(r u r) -> RIO p C(r u r t)
>           -> IO (Repository p C(t u t)

The problem I see with returning a Repository value, and indeed having type 
witnesses for repository states in the Repository type, is that they are being 
treated like normal functional values, when in fact they are just a handle to 
a single-threaded thing, namely what's actually on disk right now. In that 
sense they are like IORefs or STRefs, rather than the state in a normal state 
monad, which you can grab hold and keep an old copy of while writing a new 
state into the monad.

So the RIO type properly models this single-threadedness for the tentative 
state, but not for the recorded or unrecorded state. It was the intuition 
that any of these states could change that was behind the original 
suggestion Jason mentioned that RIO should take two parameters of type 
(RepoInState r u t) - the RepoInState type just serving to cut down the 
number of direct parameters to RIO. Repository should just be Repository p 
- the actual state it's in would be determined by the current RIO type 
parameters.

The way I see this approach working is that the RIO type would bubble all 
the way up through into Darcs.Commands.*, and only at the highest possible 
level in that would it be "lowered" back into IO.

So, in this world, we would have

data RepoInState r u t
data Repository p = ...
newtype RIO p s s' a = UnsafeRIO (Repository p -> IO a)

and then all the tentatively* code would have return types like

RIO p (RepoInState r u t) (RepoInState r u t') a

whereas for example a command like record -a would be (perhaps this is a bit 
too simple, but you get the idea)

RIO p (RepoInState r u r) (RepoInState u u u) a

Does this make some kind of sense, or have I completely misunderstood the 
goals of the witness addition? To me, this seems like the right long-term 
place to be, even if the short term goals are only to add safety to a 
subset of the repository affecting code - but in that case getting the 
types right from the beginning would still make sense.

Cheers,

Ganesh


More information about the darcs-users mailing list