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

Simon Peyton-Jones simonpj at microsoft.com
Tue May 29 03:21:41 EDT 2007


At the risk of becoming repetitious, let's keep refining the Wiki to give these competing proposals in their most up-to-date form.  I'm not arguing against email -- it's an excellent medium for discussion -- but having the outcomes recorded makes them accessible to a much wider audience who have not followed the detailed discussion.

Simon

| -----Original Message-----
| From: haskell-cafe-bounces at haskell.org [mailto:haskell-cafe-bounces at haskell.org] On Behalf Of Judah
| Jacobson
| Sent: 28 May 2007 19:50
| To: Adrian Hey
| Cc: haskell-cafe at haskell.org
| Subject: Re: [Haskell-cafe] Yet another top-level state proposal
|
| 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
| _______________________________________________
| Haskell-Cafe mailing list
| Haskell-Cafe at haskell.org
| http://www.haskell.org/mailman/listinfo/haskell-cafe


More information about the Haskell-Cafe mailing list