Double is a pretty poor choice of "whatever" (just thinking about equality of floating point numbers puts one in a state of sin :-)).
Worse still, your newChanSafe would be type-unsafe if you gave it that polymorphic type (think about it). So let's assume channels aren't polymorphic and that we were were going to use ints or strings or something as identities. Then since your newChan has got to be injective, you could just identify chan with int and be done with it. Even then, there's still quite a lot going on: Firstly, of course, the equation I wrote *does* actually hold in Haskell with the current definitions. But it would fail to hold if newchan were a non-normal form, each evaluation of which returned a new name, which was what was intended. Secondly, if you manage your own channel identities you'll end up carrying around a "current" identity/name supply and having an operation which takes a supply and gives you a fresh name and a new supply. That's just another monad (TX = supply->X*supply, gensym : Tname). If the type you use for names isn't abstract (e.g. you just use int) then the resulting equational theory will be weak (because contexts can supply all the names). A more refined treatment is possible. If (and only if) you make the type of names and their operations more abstract then there is a very nice monad just for name generation, which you could separate from the monad for actually sending and receiving values. One advantage of doing that is that the dynamic allocation monad satisfies more equations than the IO monad (it's commutative, for example). Then there's a monad morphism that lets you lift new name generation into the IO monad when you want to use the channels (IO is definitely not commutative). If you want to do fancy program transformations then this extra refinement is helpful. If you don't, having two monads instead of one just makes life even more complicated. Now, giving newChan a non-monadic type amounts to making this new name monad *implicit* - allowing divergence and/or name-generation to happen during evaluation without reflecting either possibility in the types. As I said, this breaks the equational theory of the language. But other people have taken the position that maybe it doesn't break it all that badly, and that one can make sure that the compiler's transformations respect the weaker theory [1]. This is what happens in "observable sharing", which was suggested precisely because others, like you, found doing gensym monadically in Haskell to be a bit tedious: K. Claessen and D. Sands. Observable sharing for functional circuit description. In ASIAN'99, volume 1742 of Lecture Notes in Computer Science, pages 62--73. Springer-Verlag, 1999. Names in circuit descriptions are used to express the sharing which distinguishes cyclic circuits from infinite ones. In the case of channels, however, you don't just compare the names for equality - all non-trivial uses of them are going to involve sends and receives and hence put you into the IO monad anyway. So messing up the theory of the whole language just to to have a few fewer IOs doesn't seem a good tradeoff. If you're interested in the theory, there's a big (and rapidly growing!) literature on the semantics of name generation - see the work of Pitts & Stark on the \nu-calculus, for example. To summarize the above ramble: it's an excellent question, but you almost certainly want to leave newChan where it is. Nick [1] arguably, including strict constructs (pattern matching, strict sequencing) is already a step down this road. But the Haskell/Miranda "war of the bottoms" was all a long time ago... -----Original Message----- From: S. Alexander Jacobson [mailto:[EMAIL PROTECTED] Sent: 23 April 2004 20:05 To: Nick Benton Cc: Haskell Mailing List Subject: RE: [Haskell] Why is newChan in the IO Monad? Yes, that makes sense, but I'm ok with passing in an identity. I'd like a function like this: newChanSafe::Identity -> Chan a type Identity = Double -- or whatever -Alex- _________________________________________________________________ S. Alexander Jacobson mailto:[EMAIL PROTECTED] tel:917-770-6565 http://alexjacobson.com On Fri, 23 Apr 2004, Nick Benton wrote: > Channels have identity, so allocating a new one is a side effecting > operation. Having it outside the IO monad would require (for example): > > (newChan, newChan) = (let x = newChan in (x,x)) > > which is wrong. If you wrap newChan in unsafePerformIO then the compiler > will feel free to apply rewrites like the above, which is unlikely to be > what you wanted. > > Nick > -----Original Message----- > From: [EMAIL PROTECTED] [mailto:[EMAIL PROTECTED] > On Behalf Of S. Alexander Jacobson > Sent: 23 April 2004 19:22 > To: Haskell Mailing List > Subject: [Haskell] Why is newChan in the IO Monad? > > Nothing actually happens when newChan is called > except construction of a new datastructure. It > would be nice to have non IO monad code be able to > create a new Chan that gets passed to IO code that > uses it somewhere else. > > Alternatively, is there a way to create a Chan > outside the IO monad? > > -Alex- > > _________________________________________________________________ > S. Alexander Jacobson mailto:[EMAIL PROTECTED] > tel:917-770-6565 http://alexjacobson.com > _______________________________________________ > Haskell mailing list > [EMAIL PROTECTED] > http://www.haskell.org/mailman/listinfo/haskell > _______________________________________________ Haskell mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell