[Haskell-cafe] Yet another top-level state proposal

Judah Jacobson judah.jacobson at gmail.com
Mon May 28 14:50:04 EDT 2007


On 5/26/07, Adrian Hey <ahey at iee.org> wrote:
>
> Judah Jacobson wrote:
> > In contrast to recent proposals, this one requires no extra syntax or
> > use of unsafe functions by the programmer.
>
> I'm not aware of any proposals (recent or ancient:-) that require the
> use of unsafe functions by the programmer (well apart from the
> unsafePerformIO hack itself).

I was referring to the proposal to make that hack somewhat safer by
adding a NO_INLINE_OR_CSE pragma.

> Also adding extra syntax is no problem
> these days. It's trivially simple (and indeed desirable in this case
> IMHO). It's the underlying compiler magic requires significant extra
> work I think.

Reading last week's conversation on the topic, I got the impression
that the debate is still ongoing with respect to that point.  Although
this proposal is a little less aesthetic than those for mdo or ACIO, I
think the fact that it touches so few parts of the language might make
some people more comfortable with it.  In particular, an
implementation only needs to:

- add the OnceInit/OnceIO class declarations (trivial)
- add the "OnceIO" deriving clause logic (in GHC, this would be
isolated to one module)
- add a NO_CSE pragma at the Core syntax level. (already suggested for
other conservative proposals).

But whether that's being *too* conservative is a matter of opinion, of course.

> > ------------------------------------------------
> > Under this proposal, we would write instead:
> > ------------------------------------------------
> > newtype UniqueRef = UniqueRef (IORef Integer)
> >                        deriving OnceIO
> >
> > instance OnceInit UniqueRef where
> >    onceInit = liftM UniqueRef (newIORef 0)
>
> A purely aesthetic objection, but to me it looks quite obfuscated
> compared to:
>
> uniqueRef :: IORef Integer
> uniqueRef <- ACIO.newIORef 0
>
> But I guess perhaps what's going on here could be made clearer with
> the right syntactic sugar :-)

If you're going to use syntactic sugar anyway, I think that negates
the main appeal of this proposal.  Instead, we could ignore deriving
clauses altogether, and add an optional keyword "oneshot" to type
declarations, e.g.:

oneshot uniqueRef :: IO (IORef Integer)
uniqueRef = newIORef 0

Now that I mention it, that idea's not too bad either...

> Finally, the useage problem I mentioned. Having to create a distinct
> type for each "top level thing with identity" (my terminology)
> seems like it could cause difficulties (probably not insoluble
> problems though).

My feeling is that most programs would use few enough TWIs that having
to declare extra types would not be a big hastle.  But I see you're
challenging that point below:

> If you look at the wiki page you'll see the device driver example I
> put there. This has two device handles at the top level (both same
> type), with a device driver API that takes either the device handle
> itself or a device session handle (which will contain the corresponding
> device handle) as parameters (so in principle it can be used with any
> number of devices provided the corresponding device handles are
> available).
>
> My question is, what would this example look like using the solution
> you propose? I can think of at least two possibilities, both of which
> seem quite awkward. But I'll leave it to you to think about this
> with a bit more care than perhaps I have. It'd be nice to see the
> solution on the Wiki too.
>

If you want several different devices, you could wrap them all in one
large type:

data DeviceHandle = ...
createDeviceHandle :: BaseAddress -> IO DeviceHandle

data AllHandles = AllHandles {handle1, handle2 :: DeviceHandle} deriving OnceIO

instance OnceInit AllHandles where
    onceInit = liftM2 AllHandles
                 (createDeviceHandle baseAddress1)
                 (createDeviceHandle baseAddress2)

device1, device2 :: IO DeviceHandle
device1 = liftM handle1 runOnce
device2 = liftM handle2 runOnce

This proposal does seem to encourage consolidating TWIs into one part
of the program; from a design perspective, that may not be entirely a
bad thing.

Best,
-Judah


More information about the Haskell-Cafe mailing list