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