Re: [Haskell-cafe] Re: [Haskell] Top Level -

2008-09-07 Thread Curt Sampson
On 2008-08-28 14:45 -0700 (Thu), Jonathan Cast wrote:

 Now, I happen to know that the only top-level handles that can be
 established without issuing an open system call are
 
 stdin
 stdout
 stderr
 
 (unless you're happy to have your global nonStdErr start its life
 attached to an unopened FD).

I've not thought through exactly how this might relate to your argument,
but certainly, though there might or might not be Haskell Handles for
other file descriptors, they can start out open without calling open.
Compile this simple program:

#import stdio.h

int main() {
int n;
n = write(5, foobar\n, 7);
printf(write returned %d\n, n);
return 0;
}

and run it with ./a.out 51 and have a look at the result you get.

cjs
-- 
Curt Sampson   [EMAIL PROTECTED]+81 90 7737 2974   
Mobile sites and software consulting: http://www.starling-software.com
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


The IO sin bin [was: Re: [Haskell-cafe] Re: [Haskell] Top Level -]

2008-09-04 Thread wren ng thornton

Adrian Hey wrote:

There's shed loads of information and semantic subtleties about pretty
much any operation you care to think of in the IO monad that isn't
communicated by it's type. All you know for sure is that it's weird,
because if it wasn't it wouldn't be in the IO monad.

So I think you're applying double standards.


Not to throw any more fuel on the fire (if at all possible), but the 
reason behind this is that IO has become a sin bin for all the things 
that people either don't know how to deal with, or don't care enough to 
tease apart. There are many people who would like to break IO apart into 
separate segments for all the different fragments of the RealWorld that 
actually matter for a given purpose. To date it has not been entirely 
clear how best to do this and retain a workable language.


The fact that this discussion is going on at all is, IMO, precisely 
because of the sin-bin nature of IO. People have things they want to 
have global or otherwise arbitrarily large scope, but the only notion 
of a globe in Haskell is the RealWorld. Hence they throw things into IO 
and then unsafePerformIO it to get it back out. There are three problems 
to this approach:


(1) It's a hack and not guaranteed to work, nuff said.

(2) The RealWorld is insufficiently described to ensure any semantics 
regarding *how* it holds onto the state requested of it. This problem 
manifests itself in the discussion of loading the same library multiple 
times, having multiple RTSes in a single OS process, etc. In those 
scenarios what exactly the RealWorld is and how the baton is passed 
among the different libraries/threads/processes/RTSes is not clearly 
specified.


(3) The API language is insufficiently detailed to make demands on what 
the RealWorld holds. This problem manifests itself in the argument about 
whether libraries should be allowed to implicitly modify portions of the 
RealWorld, or whether this requirement should be made clear in the type 
signatures of the library.



As I said in the thread on [Research language vs. professional 
language], I think coming up with a solution to this issue is still an 
open research problem, and one I think Haskell should be exploring.


The ACIO monad has a number of nice properties and I think it should be 
broken out from IO even if top-level - aren't added to the language. 
The ability to declare certain FFI calls as ACIO rather than IO is, I 
think, reason enough to pursue ACIO on its own. But, ACIO does not solve 
the dilemmas raised in #2 and #3. Top-level mutable state is only a 
symptom of the real problem that IO and the RealWorld are insufficiently 
described.


Another example where unsafePerformIO is used often is when doing RTS 
introspection. Frequently, interrogating the RTS has ACIO-like 
properties in that we are only interested in the RTS if a particular 
thunk happens to get pulled on, and we're only interested at the time 
that the pulling occurs rather than in sequence to any other actions. 
The use of unsafePerformIO here seems fraught with all the same problems 
as top-level mutable state. It would be nice to break out an RTS monad 
(or an UnsafeGhcRTS monad, or what have you) in order to be more clear 
about the exact requirements of what's going on.


But even if we break ACIO and UnsafeGhcRTS out from IO, the dilemmas 
remain. To a certain extent, the dilemmas will always remain because 
there will always be a frontier beyond which we don't know what's 
happening: the real world exists, afterall. However, there is still room 
to hope for a general approach to the problem.


One potential is to follow on the coattails of _Data Types a la Carte_. 
Consider, for example, if the language provided a mechanism for users to 
generate RealWorld-like non-existent tokens. Now consider removing IO[1] 
and only using BS, where the thread-state parameter could be any 
(co)product of RealWorld-like tokens. We could then have an overloaded 
function to lift any (BS a) into a BS (a :+: b). There are some 
complications with DTalC's coproducts in practice. For example, (a :+: 
b) and (b :+: a) aren't considered the same type, as naturally they 
can't be due to the Inl/Inr tagging. A similar approach should be able 
to work however, since these tokens don't really exist at all.


Of course, once we take things to that level we're already skirting 
around capability systems. Rather than using an ad-hoc approach like 
this, I think it would be better to work out a theory connecting 
capability systems to monad combinators, and then use that theory to 
smash the sin bin of IO.



[1] Or leaving it in as a type alias for BS RealWorld.

--
Live well,
~wren
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


RE: [Haskell-cafe] Re: [Haskell] Top Level -

2008-09-03 Thread Sittampalam, Ganesh
Ashley Yakeley wrote: 

Ganesh Sittampalam wrote:
 In any case, what I'm trying to establish below is that it should be
a 
 safety property of - that the entire module (or perhaps mutually 
 recursive groups of them?) can be duplicated safely - with a new
name, 
 or as if with a new name - and references to it randomly rewritten to

 the duplicate, as long as the result still type checks.

 That's not acceptable. This would cause Unique to break, 
 as its MVar would be created twice. It would also mean 
 that individual Unique and IOWitness values created by
 - would have different values depending on which bit 
 of code was referencing them. It would render the extension
 useless as far as I can see.

The result wouldn't typecheck if two Unique values that now pointed to
the two different modules were compared.

Ganesh

==
Please access the attached hyperlink for an important electronic communications 
disclaimer: 

http://www.credit-suisse.com/legal/en/disclaimer_email_ib.html
==

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: [Haskell] Top Level -

2008-09-03 Thread David Menendez
On Wed, Sep 3, 2008 at 2:53 AM, Ashley Yakeley [EMAIL PROTECTED] wrote:

 It's worth mentioning that the current Data.Unique is part of the standard
 base library, while hs-plugins is rather experimental. Currently Data.Unique
 uses the NOINLINE unsafePerformIO hack to create its MVar. If hs-plugins
 duplicates that MVar, that's a bug in hs-plugins. It's up to a dynamic
 loader to get initialisation code correct.

Data.Unique describes itself as experimental and non-portable. The
Haskell 98 report includes NOINLINE, but also states that environments
are not required to respect it. So hs-plugins wouldn't necessarily be
at fault if it didn't support Data.Unique.

-- 
Dave Menendez [EMAIL PROTECTED]
http://www.eyrie.org/~zednenem/
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


RE: [Haskell-cafe] Re: [Haskell] Top Level -

2008-09-03 Thread Sittampalam, Ganesh
Dave Menendez wrote: 

 The Haskell 98 report includes NOINLINE, but 
 also states that environments are not required
 to respect it. So hs-plugins wouldn't necessarily
 be at fault if it didn't support Data.Unique.

Also, the definition of NOINLINE in the report doesn't
preclude copying both the MVar *and* its use sites,
which is what I am proposing should be considered
generally safe.

Ganesh

==
Please access the attached hyperlink for an important electronic communications 
disclaimer: 

http://www.credit-suisse.com/legal/en/disclaimer_email_ib.html
==

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


RE: [Haskell-cafe] Re: [Haskell] Top Level -

2008-09-03 Thread Sittampalam, Ganesh
Ashley Yakeley wrote:

 To solve this the hs-plugins dynamic loader maintains
 state storing a list of what modules and packages have
 been loaded already. If load is called on a module that
 is already loaded, or dependencies are attempted to load,
 that have already been loaded, the dynamic loader ignores
 these extra dependencies. This makes it quite easy to 
 write an application that will allows an arbitrary number
 of plugins to be loaded.
 http://www.cse.unsw.edu.au/~dons/hs-plugins/hs-plugins-Z-H-6.html

My recollection from using it a while ago is that if a
module is used in the main program it will still be
loaded once more in the plugin loader. This is because
the plugin loader is basically an embedded copy of ghci
without much knowledge of the host program's RTS.

Cheers,

Ganesh

==
Please access the attached hyperlink for an important electronic communications 
disclaimer: 

http://www.credit-suisse.com/legal/en/disclaimer_email_ib.html
==

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: [Haskell] Top Level -

2008-09-03 Thread Yitzchak Gale
Ashley Yakeley wrote:
 Currently Data.Unique uses the NOINLINE unsafePerformIO
 hack to create its MVar. If hs-plugins duplicates that MVar,
 that's a bug in hs-plugins.

Sittampalam, Ganesh wrote:
 Also, the definition of NOINLINE in the report doesn't
 preclude copying both the MVar *and* its use sites,

Right. It would not be a bug in hs-plugins. That is the most
urgent problem right now.

It is nice to discuss various proposed new language
features. That is the way to solve the problem in
the long term.

But right now - there is no way to do this in Haskell at
all. The NOINLINE unsafePerformIO hack doesn't really
work. This is currently a major hole in Haskell in my
opinion.

For the short term - can we *please* get an ONLYONCE
pragma that has the correct semantics?

Thanks,
Yitz
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


RE: [Haskell-cafe] Re: [Haskell] Top Level -

2008-09-03 Thread Sittampalam, Ganesh
Yitzhak Gale wrote:

 Right. It would not be a bug in hs-plugins. That is
 the most urgent problem right now.
[...]
 For the short term - can we *please* get an ONLYONCE
 pragma that has the correct semantics?

So the purpose of this pragma would solely be so that
you can declare hs-plugins buggy for not respecting it?
Or do you have some way to fix hs-plugins so that it
does do so?

(Assuming that my belief about how hs-plugins works is
correct, of course)

Ganesh

==
Please access the attached hyperlink for an important electronic communications 
disclaimer: 

http://www.credit-suisse.com/legal/en/disclaimer_email_ib.html
==

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: [Haskell] Top Level -

2008-09-03 Thread Yitzchak Gale
I wrote:
 For the short term - can we *please* get an ONLYONCE
 pragma that has the correct semantics?

Sittampalam, Ganesh wrote:
 So the purpose of this pragma would solely be so that
 you can declare hs-plugins buggy for not respecting it?

No, the hs-plugins problem - whether hypothetical or
real - is only a symptom.

There is no way to define global variables in Haskell
right now. The NOINLINE hack is used, and most often
works. But really it's broken and there are no guarantees,
because NOINLINE does not have the right semantics.
This is demonstrated by your hs-plugins example, but
it's a general problem.

Until a permanent solution is implemented and deployed
in the compilers (if ever), can we please have a pragma
that allows the current hack to really work?

Thanks,
Yitz
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


RE: [Haskell-cafe] Re: [Haskell] Top Level -

2008-09-03 Thread Sittampalam, Ganesh
(apologies for misspelling your name when quoting you last time) 
Yitzchak Gale wrote:
 For the short term - can we *please* get an ONLYONCE pragma that has

 the correct semantics?

 Until a permanent solution is implemented and deployed in the 
 compilers (if ever), can we please have a pragma that allows
 the current hack to really work?

How do you propose that this pragma would be implemented?

Ganesh

==
Please access the attached hyperlink for an important electronic communications 
disclaimer: 

http://www.credit-suisse.com/legal/en/disclaimer_email_ib.html
==

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: [Haskell] Top Level -

2008-09-03 Thread Yitzchak Gale
 For the short term - can we *please* get an ONLYONCE pragma that has
 the correct semantics?

Sittampalam, Ganesh wrote:
 How do you propose that this pragma would be implemented?

As far as I know now, in GHC it could currently just be
an alias for NOINLINE, but the GHC gurus could say for sure.
Except it should require a monomorphic constant - otherwise
the guarantee doesn't make sense.

And it would have clear comments and documentation
that state that it guarantees that the value will be computed
at most once. That way, bugs could be filed against it if
that ever turns out not to be true.

Other applications and libraries that support the pragma -
such as other compilers, and hs-plugins - would be required
to respect the guarantee, and bugs could be filed against
them if they don't.

Thanks,
Yitz
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


RE: [Haskell-cafe] Re: [Haskell] Top Level -

2008-09-03 Thread Sittampalam, Ganesh
Yitzchak Gale wrote

 Other applications and libraries that support the pragma - such as
other 
 compilers, and hs-plugins - would be required to respect the
guarantee, and  bugs could be filed against them if they don't.

If hs-plugins were loading object code, how would it even know of the
existence of the pragma? Given such knowledge, how would it implement
it?

Ganesh

==
Please access the attached hyperlink for an important electronic communications 
disclaimer: 

http://www.credit-suisse.com/legal/en/disclaimer_email_ib.html
==

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: [Haskell] Top Level -

2008-09-03 Thread Yitzchak Gale
I wrote
 Other applications and libraries that support the pragma -
 such as other compilers, and hs-plugins - would be
 required to respect the guarantee, and bugs could be
 filed against them if they don't.

Sittampalam, Ganesh wrote:
 If hs-plugins were loading object code, how would it even
 know of the existence of the pragma? Given such
 knowledge, how would it implement it?

Good point. A compiler pragma is only that, in the end.
This is just a hack, we can only do the best we can
with it.

Regards,
Yitz
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: [Haskell] Top Level -

2008-09-03 Thread David Menendez
On Wed, Sep 3, 2008 at 9:30 AM, Yitzchak Gale [EMAIL PROTECTED] wrote:
 I wrote
 Other applications and libraries that support the pragma -
 such as other compilers, and hs-plugins - would be
 required to respect the guarantee, and bugs could be
 filed against them if they don't.

 Sittampalam, Ganesh wrote:
 If hs-plugins were loading object code, how would it even
 know of the existence of the pragma? Given such
 knowledge, how would it implement it?

 Good point. A compiler pragma is only that, in the end.
 This is just a hack, we can only do the best we can
 with it.

How does the FFI handle initialization? Presumably, we can link to
libraries that have internal state. Could someone, in principle, use
the FFI to create a global variable?

-- 
Dave Menendez [EMAIL PROTECTED]
http://www.eyrie.org/~zednenem/
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: [Haskell] Top Level -

2008-09-02 Thread Adrian Hey

Ganesh Sittampalam wrote:
You see this as a requirement that can be discharged by adding the ACIO 
concept; I see it as a requirement that should be communicated in the type.


Another way of looking at it is that Data.Unique has associated with it 
some context in which Unique values are safely comparable. You want that 
context to always be the top-level/RTS scope, I would like the defining 
that context to be part of the API.


But why pick on Data.Unique as special? Because I just happened to have
pointed out it uses a global variable? If you didn't know this I
suspect this issue just wouldn't be an issue at all. Why haven't you
raised a ticket complaining about it's API having the wrong type
sigs? :-)

There's shed loads of information and semantic subtleties about pretty
much any operation you care to think of in the IO monad that isn't
communicated by it's type. All you know for sure is that it's weird,
because if it wasn't it wouldn't be in the IO monad.

So I think you're applying double standards.


We have to have something concrete to discuss and this is the simplest.
Like I said there are a dozen or so other examples in the base package
last time I counted


Would you mind listing them? It might help provide some clarity to the 
discussion.


Here's what you can't find in the libs distributed with ghc. Note this
does not include all uses of unsafePerformIO. It only includes uses
to make a global variable.

Control.Concurrent   1
Control.OldException 1
Data.HashTable   1
Data.Typeable1
Data.Unique  1
GHC.Conc 8
GHC.Handle   3
System.Random1
Language.Haskell.Syntax  1
System.Posix.Signals 2
System.Win32.Types   1
Network.BSD  1
System.Posix.User1
Total:  23

In the ghc source you can find 16 uses of the GLOBAL_VAR macro (can't
imagine what that does :-).

I didn't even attempt to figure out how global variables might be the
rts source. Anyone care to hazard a guess?

You can find a few more in the extra libs..
Graphics.UI.GLUT.Menu1
Graphics.UI.GLUT.Callbacks.Registration  3
Graphics.Rendering.OpenGL.GLU.ErrorsInternal 1
Total:   5

A few more:
wxHaskell 6
c2hs  1
GTK2HS1
SDL   0 !!

However, I happen to know that SDL suffers from the initialisation
issue and IIRC it needs at least 1 global to stop user using an unsafe
(possibly segfault inducing) calling sequence.

Anyway, that's all from me because I'm bored with this thread now.

Regards
--
Adrian hey


___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: [Haskell] Top Level -

2008-09-02 Thread Ganesh Sittampalam

On Tue, 2 Sep 2008, Adrian Hey wrote:


Ganesh Sittampalam wrote:
You see this as a requirement that can be discharged by adding the ACIO 
concept; I see it as a requirement that should be communicated in the type.


Another way of looking at it is that Data.Unique has associated with it 
some context in which Unique values are safely comparable. You want that 
context to always be the top-level/RTS scope, I would like the defining 
that context to be part of the API.


But why pick on Data.Unique as special? Because I just happened to have
pointed out it uses a global variable?


Only because I thought it was the running example.

If you didn't know this I suspect this issue just wouldn't be an issue 
at all. Why haven't you raised a ticket complaining about it's API 
having the wrong type sigs? :-)


Because I don't use it, and even if I did use it I would just live with 
the API it has.



There's shed loads of information and semantic subtleties about pretty
much any operation you care to think of in the IO monad that isn't
communicated by it's type. All you know for sure is that it's weird,
because if it wasn't it wouldn't be in the IO monad.


It does actually claim a specification, namely that no two calls to 
newUnique return values that compare equal.



We have to have something concrete to discuss and this is the simplest.
Like I said there are a dozen or so other examples in the base package
last time I counted


Would you mind listing them? It might help provide some clarity to the 
discussion.


Here's what you can't find in the libs distributed with ghc. Note this
does not include all uses of unsafePerformIO. It only includes uses
to make a global variable.


Thanks. It'd probably be a good addition to the wiki page on this topic 
for these to be catalogued in terms of why they are needed, though I'm 
(probably) not volunteering to do it :-)


Ganesh
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: [Haskell] Top Level -

2008-09-01 Thread Adrian Hey

Ganesh Sittampalam wrote:
On Sun, 31 Aug 2008, Adrian Hey wrote: 

Eh? Please illustrate your point with Data.Unique. What requirements
does it place on it's context? (whatever that might mean :-)


It requires that its context initialises it precisely once.


It's context being main? If so this is true, but I don't see why this
is  a problem. It's a happy accident with the unsafePerformIO hack
as it is, and part of the defined semantics for *all* hypothetical
top level - bindings. Though to be more precise, the requirement
is that it may be initialised at any time prior to first use, but
never again (there's no requirement to initialise it at all if
it isn't used). Also ACIO monad properties guarantee that it's
always initialised to the same value regardless of when this occurs.
So I don't see the problem.

Data.Unique is actually a poor example, as it is actually fine to 
initialise it multiple times as long as the resulting Unique values 
aren't treated as coming from the same datatype.


I just don't see what you're getting at. There's no problem here
and Data.Unique is not special. We don't even have to consider
whether or not it's OK to reinitialise these things unless the
programmer explicitly allows this in the API (which Data.Unique
doesn't). This is true for all top level - bindings.

myCount :: MVar Int
myCount - newMVar 0

In a hypothetical second initialisation, do you mean..
1 - myCount somehow gets rebound to a different/new MVar
2 - The binding stays the same but MVar gets reset to 0 without
this being explicitly done in the code.

I assume you mean the latter (2). But either case seems like an
absurdity to me. No top level bindings randomly change halfway
through a program and MVars (I hope) are not prone to random
corruption (no need to suppose things are any different if they
occur at the top level).

But equally it can be 
implemented with IORefs,


Actually it couldn't as IORefs are not an Ord instance.

so it's not a good advert for the need for 
global variables.


Oh please!

We have to have something concrete to discuss and this is the simplest.
Like I said there are a dozen or so other examples in the base package
last time I counted and plenty of people have found that other libs/ffi
bindings need them for safety reasons. Or at least they need something
that has global main/process scope and so far the unsafePerformIO hack
is the only known way to get that and still keep APIs stable,sane and
modular.

Also, AFAICS going the way that seems to be suggested of having all this
stuff reflected in the arguments/types of API is going to make it
practically impossible to have platform independent APIs if all platform
specific implementation detail has to be accounted for in this way.


The real irony of your remark is that making APIs this robust is
practically impossible *without* using global variables, and you're
now saying that because they've done this work to eliminate these
constraints they now have to be held to account for this with
an absurd API.


I think there are two cases to consider here.

A Data.Unique style library, which requires genuinely *internal* state, 
and which is agnostic to having multiple copies of itself loaded 
simultaneously. In that case, there is no requirement for a 
process-level scope for -, just that each instance of the library is 
only initialised once - the RTS can do this, as can any dynamic loader.


The other is some library that really cannot be safely loaded multiple 
times, because it depends on some lower-level shared resource. Such a 
library simply cannot be made safe without cooperation from the thing 
that controls that shared resource, because you cannot prevent a second 
copy of it being loaded by something you have no control over.


If the - proposal were only about supporting the first of these 
applications, I would have far fewer objections to it. But it would have 
nothing to do with process-level scope, then.


The - proposal introduces no new problems that aren't already with us.
It solves 1 problem in that at least there's no room for the compiler to
get it wrong or for people do use dangerous things when using the
unsafePerformIO hack. I think that is really the only problem that can
be solved at the level of Haskell language definition.

I also think we need to be careful about the use of the term process.

IMO when we say the process defined by main, we are talking about an
abstract process that is essentially defined by Haskell and may have
nothing in common with a process as defined by various OS's (assuming
there's an OS involved at all). Perhaps we should try be more clear and
say Haskell process or OS process as appropriate. In particular
when we say an MVar or IORef has global process scope (whether or
not it occurs at top level) we are talking about a Haskell process,
not an OS process.

The issues you raise seem to me to be more to do with correct
implementaton on various platforms using various tools of 

Re: [Haskell-cafe] Re: [Haskell] Top Level -

2008-09-01 Thread Adrian Hey

Adrian Hey wrote:

We have to have something concrete to discuss and this is the simplest.
Like I said there are a dozen or so other examples in the base package
last time I counted and plenty of people have found that other libs/ffi
bindings need them for safety reasons. Or at least they need something
that has global main/process scope and so far the unsafePerformIO hack
is the only known way to get that and still keep APIs stable,sane and
modular.


Actually all this use of the tainted and derogatory term global
variable is causing me to be imprecise. All MVars/IORefs have global 
main/process scope whether or not they're bound to something at the

top level.

The purpose of the top level static binding is to prevent accidental
or malicious state spoofing if it's important that the *same*
IORef/MVar is always used for some purpose.

Regards
--
Adrian Hey
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: [Haskell] Top Level -

2008-09-01 Thread Ganesh Sittampalam

On Mon, 1 Sep 2008, Adrian Hey wrote:


Actually all this use of the tainted and derogatory term global
variable is causing me to be imprecise. All MVars/IORefs have global 
main/process scope whether or not they're bound to something at the

top level.


Global variable is exactly the right term to use, if we are following 
the terminology of other languages. We don't call the result of malloc/new 
etc a global variable, unless it is assigned to something with top-level 
scope.


Ganesh
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: [Haskell] Top Level -

2008-09-01 Thread John Meacham
On Thu, Aug 28, 2008 at 07:21:48PM -0400, Brandon S. Allbery KF8NH wrote:
 OS provided one? What if you have an exokernel, where it is expected
 these things _will_ be implemented in the userspace code. why  
 shouldn't
 that part of the exokernel be written in haskell?

 What's stopping it?  Just wrap it in a state-carrying monad representing 
 a context.  That way you can also keep multiple contexts if necessary 
 (and I think it is often necessary, or at least desirable, with most 
 exokernel clients).

That is exactly what I want to do, with the 'IO' monad. but I would like
the IO primitives to be implementable in haskell _or_ C transparently
and efficiently. It should not matter how the primitives are
implemented.

John

-- 
John Meacham - ⑆repetae.net⑆john⑈
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: [Haskell] Top Level -

2008-09-01 Thread John Meacham
On Fri, Aug 29, 2008 at 04:33:50PM -0700, Dan Weston wrote:
 C++ faced this very issue by saying that with global data, uniqueness of  
 initialization is guaranteed but order of evaluation is not. Assuming  
 that the global data are merely thunk wrappers over some common data  
 source, this means that at minimum, there can be no data dependencies  
 between plugins where the order of evaluation matters.

Fortunately, we can do a whole lot better with haskell, the type system
guarentees that order of evaluation is irrelevant :) no need to specify
anything about implementations.

John

-- 
John Meacham - ⑆repetae.net⑆john⑈
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: [Haskell] Top Level -

2008-09-01 Thread Ganesh Sittampalam

On Mon, 1 Sep 2008, John Meacham wrote:


On Mon, Sep 01, 2008 at 10:45:05PM +0100, Ganesh Sittampalam wrote:

Actually all this use of the tainted and derogatory term global
variable is causing me to be imprecise. All MVars/IORefs have global
main/process scope whether or not they're bound to something at the
top level.


Global variable is exactly the right term to use, if we are following
the terminology of other languages. We don't call the result of
malloc/new etc a global variable, unless it is assigned to something
with top-level scope.


global variable is not a very precise term in other languages for
various platforms too a lot of times.  for instance, windows dll's have
the ability to share individual variables across all loadings of said
dll. (for better or worse.)


Interesting, is this just within a single process?

Haskell certainly has more advanced scoping capabilities than other 
languages so we need a more refined terminology. I think 'IO scope' is 
the more precise term, as it implys the scope is that of the IO monad 
state. which may or may not correspond to some external 'process scope'.


Hmm, to me that implies that if the IO monad stops and restarts, e.g. when 
a Haskell library is being called from an external library, then the scope 
stops and starts again (which I presume is not the intention of - ?)


But I don't really care that much about the name, if there is consensus on 
what to call it that doesn't cause ambiguities with OS processes etc.


Cheers,

Ganesh
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: [Haskell] Top Level -

2008-09-01 Thread Brandon S. Allbery KF8NH

On 2008 Sep 1, at 18:08, Ganesh Sittampalam wrote:

On Mon, 1 Sep 2008, John Meacham wrote:

On Mon, Sep 01, 2008 at 10:45:05PM +0100, Ganesh Sittampalam wrote:

Actually all this use of the tainted and derogatory term global
variable is causing me to be imprecise. All MVars/IORefs have  
global

main/process scope whether or not they're bound to something at the
top level.


Global variable is exactly the right term to use, if we are  
following

the terminology of other languages. We don't call the result of
malloc/new etc a global variable, unless it is assigned to  
something

with top-level scope.


global variable is not a very precise term in other languages for
various platforms too a lot of times.  for instance, windows dll's  
have

the ability to share individual variables across all loadings of said
dll. (for better or worse.)


Interesting, is this just within a single process?


Last I checked, it was across processes; that is, every DLL has its  
own (optional) data segment which is private to the DLL but shared  
across all system-wide loaded instances of the DLL.  This actually  
goes back to pre-NT Windows.


Haskell certainly has more advanced scoping capabilities than other  
languages so we need a more refined terminology. I think 'IO scope'  
is the more precise term, as it implys the scope is that of the IO  
monad state. which may or may not correspond to some external  
'process scope'.


Hmm, to me that implies that if the IO monad stops and restarts,  
e.g. when a Haskell library is being called from an external  
library, then the scope stops and starts again (which I presume is  
not the intention of - ?)


It tells me the flow of execution has temporarily exited the scope of  
the IO monad, but can return to it.  The state is suspended, not exited.


--
brandon s. allbery [solaris,freebsd,perl,pugs,haskell] [EMAIL PROTECTED]
system administrator [openafs,heimdal,too many hats] [EMAIL PROTECTED]
electrical and computer engineering, carnegie mellon universityKF8NH


___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: [Haskell] Top Level -

2008-09-01 Thread Ganesh Sittampalam

On Mon, 1 Sep 2008, Brandon S. Allbery KF8NH wrote:


On 2008 Sep 1, at 18:08, Ganesh Sittampalam wrote:

On Mon, 1 Sep 2008, John Meacham wrote:



for instance, windows dll's have
the ability to share individual variables across all loadings of said
dll. (for better or worse.)


Interesting, is this just within a single process?


Last I checked, it was across processes; that is, every DLL has its own 
(optional) data segment which is private to the DLL but shared across 
all system-wide loaded instances of the DLL.  This actually goes back to 
pre-NT Windows.


Sounds like a recipe for fun :-)

Haskell certainly has more advanced scoping capabilities than other 
languages so we need a more refined terminology. I think 'IO scope' is the 
more precise term, as it implys the scope is that of the IO monad state. 
which may or may not correspond to some external 'process scope'.


Hmm, to me that implies that if the IO monad stops and restarts, e.g. when 
a Haskell library is being called from an external library, then the scope 
stops and starts again (which I presume is not the intention of - ?)


It tells me the flow of execution has temporarily exited the scope of the IO 
monad, but can return to it.  The state is suspended, not exited.


In that case we could equally call the things library scope, as that's 
the only scope they're visible in unless exported. Anyway, as long as 
we're clear on what it means, the name doesn't really matter.


Ganesh
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: [Haskell] Top Level -

2008-09-01 Thread Ganesh Sittampalam

On Mon, 1 Sep 2008, Adrian Hey wrote:


Ganesh Sittampalam wrote:
On Sun, 31 Aug 2008, Adrian Hey wrote: 

Eh? Please illustrate your point with Data.Unique. What requirements
does it place on it's context? (whatever that might mean :-)


It requires that its context initialises it precisely once.


It's context being main? If so this is true, but I don't see why this
is  a problem. [...]  Also ACIO monad properties guarantee that it's
always initialised to the same value regardless of when this occurs.
So I don't see the problem.


You see this as a requirement that can be discharged by adding the ACIO 
concept; I see it as a requirement that should be communicated in the 
type.


Another way of looking at it is that Data.Unique has associated with it 
some context in which Unique values are safely comparable. You want that 
context to always be the top-level/RTS scope, I would like the defining 
that context to be part of the API.


Data.Unique is actually a poor example, as it is actually fine to 
initialise it multiple times as long as the resulting Unique values 
aren't treated as coming from the same datatype.


I just don't see what you're getting at. There's no problem here
and Data.Unique is not special.


See the conversation with Ashley - you can have multiple copies of 
Data.Unique loaded without problem, as long as the resulting Unique 
datatypes aren't comparable with each other.



myCount :: MVar Int
myCount - newMVar 0

In a hypothetical second initialisation, do you mean..
1 - myCount somehow gets rebound to a different/new MVar


I mean this. Or, more precisely, that a *different* myCount gets bound to 
a different MVar.



But equally it can be implemented with IORefs,


Actually it couldn't as IORefs are not an Ord instance.


Well, perhaps one could be added (along with hashing). Or perhaps it's not 
really needed; I don't know as I've never used Data.Unique, and I doubt I 
ever would as when I need a name supply I also want human readable names, 
and I can't think of any other uses for it, though no doubt some exist.



so it's not a good advert for the need for global variables.


Oh please!

We have to have something concrete to discuss and this is the simplest.
Like I said there are a dozen or so other examples in the base package
last time I counted


Would you mind listing them? It might help provide some clarity to the 
discussion.


and plenty of people have found that other libs/ffi bindings need them 
for safety reasons. Or at least they need something that has global 
main/process scope and so far the unsafePerformIO hack is the only known 
way to get that and still keep APIs stable,sane and modular.


Again, some specific examples would help.


Also, AFAICS going the way that seems to be suggested of having all this
stuff reflected in the arguments/types of API is going to make it
practically impossible to have platform independent APIs if all platform
specific implementation detail has to be accounted for in this way.


It can all be wrapped up in a single abstract context argument; the only 
platform bleed would be if one platform needed a context argument but 
others didn't.



I think there are two cases to consider here.

A Data.Unique style library, which requires genuinely *internal* state, and 
which is agnostic to having multiple copies of itself loaded 
simultaneously. In that case, there is no requirement for a process-level 
scope for -, just that each instance of the library is only initialised 
once - the RTS can do this, as can any dynamic loader.


The other is some library that really cannot be safely loaded multiple 
times, because it depends on some lower-level shared resource. Such a 
library simply cannot be made safe without cooperation from the thing that 
controls that shared resource, because you cannot prevent a second copy of 
it being loaded by something you have no control over.


If the - proposal were only about supporting the first of these 
applications, I would have far fewer objections to it. But it would have 
nothing to do with process-level scope, then.


The - proposal introduces no new problems that aren't already with us.
It solves 1 problem in that at least there's no room for the compiler to
get it wrong or for people do use dangerous things when using the
unsafePerformIO hack. I think that is really the only problem that can
be solved at the level of Haskell language definition.


I just want to be clear that the second of the two categories above cannot 
be used to justify the proposal, as it does not make them safe.



I also think we need to be careful about the use of the term process.

IMO when we say the process defined by main, we are talking about an
abstract process that is essentially defined by Haskell and may have
nothing in common with a process as defined by various OS's (assuming
there's an OS involved at all). Perhaps we should try be more clear and
say Haskell process or OS process as appropriate. In particular

Re: [Haskell-cafe] Re: [Haskell] Top Level -

2008-09-01 Thread Ganesh Sittampalam

On Mon, 1 Sep 2008, Ashley Yakeley wrote:


Ganesh Sittampalam wrote:
Right, but they might be the same package version, if one is a dynamically 
loaded bit of code and the other isn't.


OK. It's up to the dynamic loader to deal with this, and make sure that 
initialisers are not run more than once when it loads the package into the 
RTS. The scopes and names are all well-defined. How hard is this?


I have a feeling it might be non-trivial; the dynamically loaded bit of 
code will need a separate copy of the module in question, since it might 
be loaded into something where the module is not already present. So it'll 
have a separate copy of the global variable in a separate location, and 
the dynamic loader needs to arrange to do something weird, like copying 
the value of the first run - to the second one instead of running it 
again.




My question was actually about what happens with some different library 
that needs -; how do we know whether having two -s is safe or not?


I don't understand. When is it not safe?


Well, the safety of - being run twice in the Data.Unique case is based 
around the two different Data.Unique types not being compatible. Let's 
suppose some other module uses a -, but returns things based on that 
- that are some standard type, rather than a type it defines itself. Is 
module duplication still safe?


No, it seems like the right way to do introspection to me, rather than 
adding some new mechanism for describing a datatype as your paper

suggests.


Aesthetic arguments are always difficult. The best I can say is, why are 
some classes blessed with a special language-specified behaviour?


Well, let me put it this way; since I don't like -, and I don't 
particularly mind Typeable, I wouldn't accept IOWitness as an example of 
something that requires - to implement correctly, because I don't see any 
compelling feature that you can only implement with -.



We could arrange for the class member of Typeable to be called unsafe


We could, but it's not actually unsafe to call as such. It's only unsafe to 
implement.


That's fine, it can export a non-class member without the unsafe prefix.

And if we're going the implicit contract route, we have to resort to 
unsafe functions to do type representation. It's not necessary, and 
seems rather against the spirit of Haskell.


Time was when people would insist that unsafePerformIO wasn't Haskell, 
though perhaps useful for debugging. Now we have all these little unsafe 
things because people think they're necessary, and there's an implicit 
contract forced on the user not to be unsafe. But it turns out that 
they're not necessary.


There's some unsafety somewhere in both Typeable and IOWitnesses, and in 
both cases it can be completely hidden from the user - with Typeable, just 
don't let the user define the typeOf function at all themselves. I'm not 
actually sure why it is exposed; is it necessary for some use pattern?


I don't see what the point of multiple values is, I'm afraid. A single 
instance of Typeable is fine for doing type equality tests.


Sometimes you want to do witness equality tests rather than type equality 
tests. For instance, I might have a foo exception and a bar exception, 
both of which carry an Int. Rather than create new Foo and Bar types, I can 
just create a new witness for each.


This is precisely what newtype is designed for, IMO. We don't need another 
mechanism to handle it.


Cheers,

Ganesh
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: [Haskell] Top Level -

2008-08-31 Thread Adrian Hey

Dan Doel wrote:

Here's a first pass:

-- snip --

{-# LANGUAGE Rank2Types, GeneralizedNewtypeDeriving #-}

module Unique where

import Control.Monad.Reader
import Control.Monad.Trans

import Control.Concurrent.MVar

-- Give Uniques a phantom region parameter, so that you can't accidentally
-- compare Uniques from two different uniqueness sources.
newtype Unique r = Unique Integer deriving Eq

newtype U r a = U { unU :: ReaderT (MVar Integer) IO a }
  deriving (Functor, Monad, MonadIO)

-- Higher rank type for region consistency
runU :: (forall r. U r a) - IO a
runU m = newMVar 0 = runReaderT (unU m)

newUnique :: U r (Unique r)
newUnique = U (do source - ask
  val - lift $ takeMVar source
  let next = val + 1
  lift $ putMVar source next
  return $ Unique next)

-- hashUnique omitted

-- snip --

It's possible that multiple unique sources can exist in a program with this 
implementation, but because of the region parameter, the fact that a Unique 
may not be globally unique shouldn't be a problem. If your whole program 
needs arbitrary access to unique values, then I suppose something like:


main = runU realMain

realMain :: U r ()
realMain = ...

is in order.

Insert standard complaints about this implementation requiring liftIO all over 
the place if you actually want to do other I/O stuff inside the U monad.


Well that wouldn't be my main complaint :-)

Thanks for taking the time to do this Dan. I think the safety
requirement has been met, but I think it fails on the improved API.
The main complaint would be what I see as loss of modularity, in that
somehow what should be a small irrelevant detail of the implementation
of some obscure module somewhere has propogated it's way all the way
upto main.

This is something it seems to have in common with all other attempts
I've seen to solve the global variable problem without actually using
a..you know what :-) It doesn't matter whether it's explicit state
handle args, withWhateverDo wrappers, novel monads or what. They
all have this effect.

To me this seems completely at odds with what I thought was generally
accepted wisdom of how to write good maintainable, modular software.
Namely hiding as much implemention detail possible and keeping APIs
as simple and stable as they can be. I don't know if I'm alone in
that view nowadays.

I'm also not sure I understand why so many people seem to feel that
stateful effects must be accounted for somehow in the args and/or
types of the effecting function. Like if I had..

getThing :: IO Thing

..as an FFI binding, nobody would give it a moments thought. They'd
see it from it's type that it had some mysterious world state
dependent/effecting behaviour, but would be quite happy to just
accept that the didn't really need to worry about all that magic...
instead they'd accept that it just works.

Why then, if I want to implement precisely the same thing in Haskell
(using a global variable) does it suddenly become so important for
this stateful magic to be accounted for? Like the presence of that
global variable must be made so very painfully apparent in main
(and everywhere else on the dependency path too I guess).

In short, I just don't get it :-)

Purists aren't going to like it, but I think folk *will* be using real
global variables in I/O libs for the forseeable future. Seems a shame
that they'll have to do this with unsafePerformIO hack though :-(

Regards
--
Adrian Hey

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: [Haskell] Top Level -

2008-08-31 Thread Ganesh Sittampalam

On Sat, 30 Aug 2008, Adrian Hey wrote:


Ganesh Sittampalam wrote:

Well, yes, but if I implemented a library in standard Haskell it would 
always be safely serialisable/deserialisable (I think). So the global 
variables hack somehow destroys that property - how do I work out why it 
does in some cases but not others?


This has nothing to do with the use of global variables. If you have
a set of values that are guaranteed to be distinct (unique) and you
add another random/arbitrary value to that set you have no way of
knowing that it is different from any current member (other than
searching the entire set, assuming it's available).


OK, never mind about this. I was thinking that referential transparency 
was violated by remoting, but since unique values can only be constructed 
in IO, I think I was wrong.



Well, I've never seen a convincing use case for global variables :-)


Well apart from all the libs that couldn't be implemented with them...


They can't be implemented with an interface that is completely oblivious 
to the fact that the libraries require some state.


Dynamic loading and plugins work fine with standard Haskell now, because 
nothing in standard Haskell breaks them. The - proposal might well break 
them, which is a significant downside for it.


I don't see how, but if so - bindings are not the cause of the
brokeness. They'd still be broken using the unsafePerformIO hack.


Which places the unsafePerformIO hack at fault, seeing as it's unsafe and 
a hack and all :-) If - was standard then it'd be up to everyone else to 
work round its limitations.


In general, the smaller the world that the Haskell standard lives in, the 
less it can interfere with other concerns. - massively increases that 
world, by introducing the concept of a process scope.


All IORefs,MVars,Chans scope across the entire process defined by main.
Or at least they *should*, if they don't then something is already
badly wrong somewhere. This has nothing to do with whether or not they
appear at top level. This is what an IORef/MVar whatever is defined to
be.


Their scope is where they can be used, and this is something we can 
explicitly track by inspecting the program text. If they are just used in 
one part of the program, their scope is limited to that part of the 
program.



But then again, I'm sure that some that will be adamant that any way
of making global variables is a hack. But they'll still be happy
to go on using file IO, sockets etc regardless, blissfully unaware
of the hacks they are dependent on :-)


I'm not sure of precisely what you mean here, but stdin, stdout and stderr 
are things provided by the OS to a process. That's what defines them as 
having process scope, not something the Haskell language or RTS does.


Those rules aren't actually strong enough to provide a guarantee of 
process level scope.


The rules for - bindings shouldn't have to guarantee this.
This should be guaranteed by newMVar returning a new *MVar*, wherever
it's used (for example).


The issue is whether the - is run multiple times in a single process or 
not, rather than how the thing it calls behaves.



I mean semantic faults, as in the proposal just doesn't do what it
promises for some subtle reason.


It doesn't provide once-only semantics across an entire process in cases 
involving dynamic loading or two Haskell libraries together with RTS 
separately linked into the same C program. I don't know whether you intend 
that it does promise that or not, but it seems to be necessary for many of 
the applications that are used to justify it.


If you consider not giving you thread local variables a fault I guess 
you're entitled to that view, but this was never the intent of the 
proposal in the first place (that's not what people are trying to do 
when they use the unsafePerformIO hack).


The thread-local variables point was a relatively minor issue for me 
compared to the dynamic loading and related issues.


Cheers,

Ganesh
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: [Haskell] Top Level -

2008-08-31 Thread Brandon S. Allbery KF8NH

On 2008 Aug 31, at 10:20, Ganesh Sittampalam wrote:

On Sat, 30 Aug 2008, Adrian Hey wrote:

But then again, I'm sure that some that will be adamant that any way

of making global variables is a hack. But they'll still be happy
to go on using file IO, sockets etc regardless, blissfully unaware
of the hacks they are dependent on :-)


I'm not sure of precisely what you mean here, but stdin, stdout and  
stderr are things provided by the OS to a process. That's what  
defines them as having process scope, not something the Haskell  
language or RTS does.


But their representations in Haskell must have the same scope and are  
therefore de facto global variables.


--
brandon s. allbery [solaris,freebsd,perl,pugs,haskell] [EMAIL PROTECTED]
system administrator [openafs,heimdal,too many hats] [EMAIL PROTECTED]
electrical and computer engineering, carnegie mellon universityKF8NH


___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: [Haskell] Top Level -

2008-08-31 Thread Ganesh Sittampalam

On Sun, 31 Aug 2008, Brandon S. Allbery KF8NH wrote:


On 2008 Aug 31, at 10:20, Ganesh Sittampalam wrote:

I'm not sure of precisely what you mean here, but stdin, stdout and 
stderr are things provided by the OS to a process. That's what defines 
them as having process scope, not something the Haskell language or RTS 
does.


But their representations in Haskell must have the same scope and are 
therefore de facto global variables.


Yep, but this is not Haskell providing a way to make global variables, it 
is just providing an interface to ones that already exist. The point is 
that the RTS can't provide (process-scope) global variables of its own 
invention, because it can't guarantee to be running at the top-level of a 
process, which it needs to be in order to control their construction.


Cheers,

Ganesh
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: [Haskell] Top Level -

2008-08-31 Thread Brandon S. Allbery KF8NH

On 2008 Aug 31, at 10:29, Ganesh Sittampalam wrote:

On Sun, 31 Aug 2008, Brandon S. Allbery KF8NH wrote:

On 2008 Aug 31, at 10:20, Ganesh Sittampalam wrote:
I'm not sure of precisely what you mean here, but stdin, stdout  
and stderr are things provided by the OS to a process. That's what  
defines them as having process scope, not something the Haskell  
language or RTS does.


But their representations in Haskell must have the same scope and  
are therefore de facto global variables.


Yep, but this is not Haskell providing a way to make global  
variables, it is just providing an interface to ones that already  
exist. The point is that the RTS can't provide (process-scope)


But that is done the same way as providing general global variables,  
so you can't get away from it.


--
brandon s. allbery [solaris,freebsd,perl,pugs,haskell] [EMAIL PROTECTED]
system administrator [openafs,heimdal,too many hats] [EMAIL PROTECTED]
electrical and computer engineering, carnegie mellon universityKF8NH


___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: [Haskell] Top Level -

2008-08-31 Thread Ganesh Sittampalam

On Sun, 31 Aug 2008, Brandon S. Allbery KF8NH wrote:


On 2008 Aug 31, at 10:29, Ganesh Sittampalam wrote:

On Sun, 31 Aug 2008, Brandon S. Allbery KF8NH wrote:

On 2008 Aug 31, at 10:20, Ganesh Sittampalam wrote:
I'm not sure of precisely what you mean here, but stdin, stdout and 
stderr are things provided by the OS to a process. That's what defines 
them as having process scope, not something the Haskell language or RTS 
does.


But their representations in Haskell must have the same scope and are 
therefore de facto global variables.


Yep, but this is not Haskell providing a way to make global variables, it 
is just providing an interface to ones that already exist. The point is 
that the RTS can't provide (process-scope)


But that is done the same way as providing general global variables, so you 
can't get away from it.


I don't follow what you mean. stdin, stdout and stderr are just file 
descriptors 0, 1 and 2, aren't they? You can create them as many times as 
you want with using that information without causing any confusion or 
conflict. Whereas the - proposal has a once-only requirement.


Ganesh
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: [Haskell] Top Level -

2008-08-31 Thread Brandon S. Allbery KF8NH

On 2008 Aug 31, at 10:34, Ganesh Sittampalam wrote:

On Sun, 31 Aug 2008, Brandon S. Allbery KF8NH wrote:

On 2008 Aug 31, at 10:29, Ganesh Sittampalam wrote:

On Sun, 31 Aug 2008, Brandon S. Allbery KF8NH wrote:

On 2008 Aug 31, at 10:20, Ganesh Sittampalam wrote:
I'm not sure of precisely what you mean here, but stdin, stdout  
and stderr are things provided by the OS to a process. That's  
what defines them as having process scope, not something the  
Haskell language or RTS does.
But their representations in Haskell must have the same scope and  
are therefore de facto global variables.
Yep, but this is not Haskell providing a way to make global  
variables, it is just providing an interface to ones that already  
exist. The point is that the RTS can't provide (process-scope)


But that is done the same way as providing general global  
variables, so you can't get away from it.


I don't follow what you mean. stdin, stdout and stderr are just file  
descriptors 0, 1 and 2, aren't they? You can create them as many  
times as you want with using that information without causing any  
confusion or conflict. Whereas the - proposal has a once-only  
requirement.


The convention is to provide buffered versions to improve the  
performance of file I/O.  These buffered filehandles must be created  
once per runtime instance (and ideally once per process so multiple  
runtimes don't find themselves overwriting each others' output).


--
brandon s. allbery [solaris,freebsd,perl,pugs,haskell] [EMAIL PROTECTED]
system administrator [openafs,heimdal,too many hats] [EMAIL PROTECTED]
electrical and computer engineering, carnegie mellon universityKF8NH


___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: [Haskell] Top Level -

2008-08-31 Thread Ganesh Sittampalam

On Sun, 31 Aug 2008, Adrian Hey wrote:

Thanks for taking the time to do this Dan. I think the safety 
requirement has been met, but I think it fails on the improved API. The 
main complaint would be what I see as loss of modularity, in that 
somehow what should be a small irrelevant detail of the implementation 
of some obscure module somewhere has propogated it's way all the way 
upto main.


That's the key point, as I see it - they aren't irrelevant details of the 
implementation, they are requirements the implementation places on its 
context in order for that implementation to be correct. So they should be 
communicated appropriately.



To me this seems completely at odds with what I thought was generally
accepted wisdom of how to write good maintainable, modular software.
Namely hiding as much implemention detail possible and keeping APIs
as simple and stable as they can be. I don't know if I'm alone in
that view nowadays.


It's no problem to hide implementation detail, but I don't think you 
should hide the *requirement* of the implementation that it has 
constraints on how it is called, namely that it requires once-only 
initialisation or whatever.



Purists aren't going to like it, but I think folk *will* be using real
global variables in I/O libs for the forseeable future. Seems a shame
that they'll have to do this with unsafePerformIO hack though :-(


From a purist point of view, it's a shame that they choose to do it at 

all :-)

Ganesh
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: [Haskell] Top Level -

2008-08-31 Thread Ganesh Sittampalam

On Sun, 31 Aug 2008, Brandon S. Allbery KF8NH wrote:


On 2008 Aug 31, at 10:34, Ganesh Sittampalam wrote:


I don't follow what you mean. stdin, stdout and stderr are just file 
descriptors 0, 1 and 2, aren't they? You can create them as many times as 
you want with using that information without causing any confusion or 
conflict. Whereas the - proposal has a once-only requirement.


The convention is to provide buffered versions to improve the performance of 
file I/O.  These buffered filehandles must be created once per runtime 
instance (and ideally once per process so multiple runtimes don't find 
themselves overwriting each others' output).


In that case it seems that any library that might be used from a runtime 
that isn't the top-level of a process should avoid doing IO to those 
handles, for fear of producing output corruption?


Ganesh
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: [Haskell] Top Level -

2008-08-31 Thread Brandon S. Allbery KF8NH

On 2008 Aug 31, at 10:44, Ganesh Sittampalam wrote:

On Sun, 31 Aug 2008, Brandon S. Allbery KF8NH wrote:

On 2008 Aug 31, at 10:34, Ganesh Sittampalam wrote:
I don't follow what you mean. stdin, stdout and stderr are just  
file descriptors 0, 1 and 2, aren't they? You can create them as  
many times as you want with using that information without causing  
any confusion or conflict. Whereas the - proposal has a once- 
only requirement.


The convention is to provide buffered versions to improve the  
performance of file I/O.  These buffered filehandles must be  
created once per runtime instance (and ideally once per process so  
multiple runtimes don't find themselves overwriting each others'  
output).


In that case it seems that any library that might be used from a  
runtime that isn't the top-level of a process should avoid doing IO  
to those handles, for fear of producing output corruption?



You handle it the same way you handle I/O with concurrency:  either  
one of the runtimes is privileged to the extent that it owns the  
filehandles and other runtimes must make an inter-runtime call to use  
them, or the filehandle structures include locking and are shared  
across runtimes.  Both of these are used in Haskell (see most GUI  
libraries for the former, and the implementation of Handles for the  
latter).


--
brandon s. allbery [solaris,freebsd,perl,pugs,haskell] [EMAIL PROTECTED]
system administrator [openafs,heimdal,too many hats] [EMAIL PROTECTED]
electrical and computer engineering, carnegie mellon universityKF8NH


___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: [Haskell] Top Level -

2008-08-31 Thread Adrian Hey

Ganesh Sittampalam wrote:

On Sun, 31 Aug 2008, Adrian Hey wrote:

Thanks for taking the time to do this Dan. I think the safety 
requirement has been met, but I think it fails on the improved API. 
The main complaint would be what I see as loss of modularity, in that 
somehow what should be a small irrelevant detail of the implementation 
of some obscure module somewhere has propogated it's way all the way 
upto main.


That's the key point, as I see it - they aren't irrelevant details of 
the implementation, they are requirements the implementation places on 
its context in order for that implementation to be correct. So they 
should be communicated appropriately.


Eh? Please illustrate your point with Data.Unique. What requirements
does it place on it's context? (whatever that might mean :-)

It just does what it says on the tin AFAICS. There are no requirements
it places on clients (to use an OO term), as should any halfway
decent API IMO.


To me this seems completely at odds with what I thought was generally
accepted wisdom of how to write good maintainable, modular software.
Namely hiding as much implemention detail possible and keeping APIs
as simple and stable as they can be. I don't know if I'm alone in
that view nowadays.


It's no problem to hide implementation detail, but I don't think you 
should hide the *requirement* of the implementation that it has 
constraints on how it is called, namely that it requires once-only 
initialisation or whatever.


No decent API should require this. Data.Unique certainly doesn't.
In fact is debatable whether any API should requre an initalisation
call at all before other stuff should be called (the other stuff
check initialisation has occured and do it itself if necessary).

The real irony of your remark is that making APIs this robust is
practically impossible *without* using global variables, and you're
now saying that because they've done this work to eliminate these
constraints they now have to be held to account for this with
an absurd API.

Seems like a clear case of no good deed going unpunished :-)

Regards
--
Adrian Hey

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: [Haskell] Top Level -

2008-08-31 Thread Brandon S. Allbery KF8NH

On 2008 Aug 31, at 11:20, Ganesh Sittampalam wrote:

On Sun, 31 Aug 2008, Brandon S. Allbery KF8NH wrote:

On 2008 Aug 31, at 10:44, Ganesh Sittampalam wrote:
In that case it seems that any library that might be used from a  
runtime that isn't the top-level of a process should avoid doing  
IO to those handles, for fear of producing output corruption?


You handle it the same way you handle I/O with concurrency:  either  
one of the runtimes is privileged to the extent that it owns the  
filehandles and other runtimes must make an inter-runtime call to  
use them, or the filehandle structures include locking and are  
shared across runtimes.  Both of these are used in Haskell (see  
most GUI libraries for the former, and the implementation of  
Handles for the latter).


Where do the filehandle structures live in the latter case?



The place you clearly think so little of that you need to ask:   
process-global (or process-local depending on how you think about it)  
storage.  And everything in that storage must have locking.  (And this  
requirement makes it similar in some ways to other non-directly- 
accessible process state such as (say) the process id.)


--
brandon s. allbery [solaris,freebsd,perl,pugs,haskell] [EMAIL PROTECTED]
system administrator [openafs,heimdal,too many hats] [EMAIL PROTECTED]
electrical and computer engineering, carnegie mellon universityKF8NH


___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: [Haskell] Top Level -

2008-08-31 Thread Ganesh Sittampalam

On Sun, 31 Aug 2008, Brandon S. Allbery KF8NH wrote:


On 2008 Aug 31, at 11:20, Ganesh Sittampalam wrote:



Where do the filehandle structures live in the latter case?


The place you clearly think so little of that you need to ask: 
process-global (or process-local depending on how you think about it) 
storage.  And everything in that storage must have locking.


I'm sorry if this makes me seem ignorant, but I'd never heard of such a 
thing before. What is the API for accessing such storage, and/or where can 
I find its documentation?


Cheers,

Ganesh
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: [Haskell] Top Level -

2008-08-31 Thread Ganesh Sittampalam

On Sun, 31 Aug 2008, Adrian Hey wrote:


Ganesh Sittampalam wrote:

On Sun, 31 Aug 2008, Adrian Hey wrote:

Thanks for taking the time to do this Dan. I think the safety requirement 
has been met, but I think it fails on the improved API. The main complaint 
would be what I see as loss of modularity, in that somehow what should be 
a small irrelevant detail of the implementation of some obscure module 
somewhere has propogated it's way all the way upto main.


That's the key point, as I see it - they aren't irrelevant details of the 
implementation, they are requirements the implementation places on its 
context in order for that implementation to be correct. So they should be 
communicated appropriately.


Eh? Please illustrate your point with Data.Unique. What requirements
does it place on it's context? (whatever that might mean :-)


It requires that its context initialises it precisely once.

Data.Unique is actually a poor example, as it is actually fine to 
initialise it multiple times as long as the resulting Unique values aren't 
treated as coming from the same datatype. But equally it can be 
implemented with IORefs, so it's not a good advert for the need for global 
variables.



The real irony of your remark is that making APIs this robust is
practically impossible *without* using global variables, and you're
now saying that because they've done this work to eliminate these
constraints they now have to be held to account for this with
an absurd API.


I think there are two cases to consider here.

A Data.Unique style library, which requires genuinely *internal* state, 
and which is agnostic to having multiple copies of itself loaded 
simultaneously. In that case, there is no requirement for a process-level 
scope for -, just that each instance of the library is only initialised 
once - the RTS can do this, as can any dynamic loader.


The other is some library that really cannot be safely loaded multiple 
times, because it depends on some lower-level shared resource. Such a 
library simply cannot be made safe without cooperation from the thing that 
controls that shared resource, because you cannot prevent a second copy of 
it being loaded by something you have no control over.


If the - proposal were only about supporting the first of these 
applications, I would have far fewer objections to it. But it would have 
nothing to do with process-level scope, then.


Ganesh
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: [Haskell] Top Level -

2008-08-31 Thread Brandon S. Allbery KF8NH

On 2008 Aug 31, at 12:01, Ganesh Sittampalam wrote:

On Sun, 31 Aug 2008, Brandon S. Allbery KF8NH wrote:

On 2008 Aug 31, at 11:20, Ganesh Sittampalam wrote:

Where do the filehandle structures live in the latter case?


The place you clearly think so little of that you need to ask:  
process-global (or process-local depending on how you think about  
it) storage.  And everything in that storage must have locking.



You'll have to look at specific implementations.  One that I can think  
of off the top of my head is Perl 5's ithreads; there is a  
distinguished allocation store which is global to all ithreads, and  
the interpreter instance gives you primitives for locking and mutexing  
(see use threads::shared;).


--
brandon s. allbery [solaris,freebsd,perl,pugs,haskell] [EMAIL PROTECTED]
system administrator [openafs,heimdal,too many hats] [EMAIL PROTECTED]
electrical and computer engineering, carnegie mellon universityKF8NH


___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: [Haskell] Top Level -

2008-08-30 Thread Ganesh Sittampalam

On Sat, 30 Aug 2008, Adrian Hey wrote:


Ganesh Sittampalam wrote:
Will Data.Unique still work properly if a value is sent across a RPC 
interface?


A value of type Unique you mean? This isn't possible. Data.Unique has 
been designed so cannot be Shown/Read or otherwise 
serialised/deserialised (for obvious reasons I guess).


How do the implementers of Data.Unique know that they musn't let them be 
serialised/deserialised? What stops the same rule from applying to 
Data.Random?



Also what if I want a thread-local variable?


Well actually I would say that threads are bad concurrency model so
I'm not keen on thread local state at all. Mainly because I'd like to
get rid of threads, but also a few other doubts even if we keep
threads.


Even if you don't like them, people still use them.


AFAICS this is irrelvant for the present discussions as Haskell doesn't
support thread local variable thingies. If it ever does being precise
about that is someone elses problem.


The fact that your proposal isn't general enough to handle them is a mark 
against it; standardised language features should be widely applicable, 
and as orthogonal as possible to other considerations.


For the time being the scope of IORefs/MVars/Chans is (and should 
remain) whatever process is described by main (whether or not they 
appear at top level).


And if main isn't the entry point? This comes back to my questions about 
dynamic loading.


(I.E. Just making existing practice *safe*, at least in the sense that 
the compiler ain't gonna fcuk it up with INLINING or CSE and every one 
understands what is and isn't safe in ACIO)


Creating new language features means defining their semantics rather more 
clearly than just no inlining or cse, IMO.


I wouldn't even know how to go about that to the satisfaction of
purists. But global variables *are* being used whether or not the top
level - bindings are implemented. They're in the standard libraries!

So if this stuff matters someone had better figure it out :-)


It's a hack that isn't robust in many situations. We should find better 
ways to do it, not standardise it.


Cheers,

Ganesh
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: [Haskell] Top Level -

2008-08-30 Thread Adrian Hey

Ganesh Sittampalam wrote:
How do the implementers of Data.Unique know that they musn't let them be 
serialised/deserialised?


Because if you could take a String and convert it to a Unique there
would be no guarantee that result was *unique*.


What stops the same rule from applying to Data.Random?


Well the only data type defined by this is StdGen, which is a Read/Show
instance. I guess there's no semantic problem with that (can't think of
one off hand myself).


Also what if I want a thread-local variable?


Well actually I would say that threads are bad concurrency model so
I'm not keen on thread local state at all. Mainly because I'd like to
get rid of threads, but also a few other doubts even if we keep
threads.


Even if you don't like them, people still use them.


AFAICS this is irrelvant for the present discussions as Haskell doesn't
support thread local variable thingies. If it ever does being precise
about that is someone elses problem.


The fact that your proposal isn't general enough to handle them is a 
mark against it; standardised language features should be widely 
applicable, and as orthogonal as possible to other considerations.


I think the whole thread local state thing is a complete red herring.

I've never seen a convincing use case for it and I suspect the only
reason these to issues have become linked is that some folk are so
convinced that global variables are evil, they mistakenly think
thread local variables must be less evil (because they are less
global).

Anyway, if you understand the reasons why all the real world libraries
that do currently use global variables do this, it's not hard to see
why they don't want this to be thread local (it would break all the
safety properties they're trying to ensure). So whatever problem thread
local variables might solve, it isn't this one.

For the time being the scope of IORefs/MVars/Chans is (and should 
remain) whatever process is described by main (whether or not they 
appear at top level).


And if main isn't the entry point? This comes back to my questions about 
dynamic loading.


Well you're talking about some non-standard Haskell, so with this and
other non standard stuff (like plugins etc) I guess the answer is
it's up to whoever's doing this to make sure they do it right. I
can't comment further as I don't know what it is they're trying
to do, but AFAICS it's not a language design issue at present.

If plugins breaks is down to plugins to fix itself, at least until such
time as a suitable formal theory of plugins has been developed so
it can become standard Haskell :-)

(I.E. Just making existing practice *safe*, at least in the sense 
that the compiler ain't gonna fcuk it up with INLINING or CSE and 
every one understands what is and isn't safe in ACIO)


Creating new language features means defining their semantics rather 
more clearly than just no inlining or cse, IMO.


I wouldn't even know how to go about that to the satisfaction of
purists. But global variables *are* being used whether or not the top
level - bindings are implemented. They're in the standard libraries!

So if this stuff matters someone had better figure it out :-)


It's a hack that isn't robust in many situations. We should find better 
ways to do it, not standardise it.


Nobody's talking about standardising the current hack. This the whole
point of the top level - proposal, which JM seems to think is sound
enough for incorporation into JHC (correctly IMO). Nobody's found
fault with it, other than the usual global variables are evil mantra
:-)

Regards
--
Adrian Hey

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: [Haskell] Top Level -

2008-08-30 Thread Ganesh Sittampalam

On Sat, 30 Aug 2008, Ashley Yakeley wrote:


Ganesh Sittampalam wrote:
If you want to standardise a language feature, you have to explain its 
behaviour properly. This is one part of the necessary explanation.


To be concrete about scenarios I was considering, what happens if:

 - the same process loads two copies of the GHC RTS as part of two 
completely independent libraries? For added complications, imagine that 
one of the libraries uses a different implementation instead (e.g. Hugs)


 - one Haskell program loads several different plugins in a way that 
allows Haskell values to pass across the plugin boundary


How do these scenarios work with use cases for - like (a) Data.Unique and 
(b) preventing multiple instantiation of a sub-library?


That's a good question. But before you propose these scenarios, you must 
establish that they are sane for Haskell as it is today.


In particular, would _local_ IORefs work correctly? After all, the memory 
allocator must be global in some sense. Could you be sure that different 
calls to newIORef returned separate IORefs?


Yes, I would expect that. Allocation areas propagate downwards from the OS 
to the top-level of a process and then into dynamically loaded modules if 
necessary. Any part of this puzzle that fails to keep them separate (in 
some sense) is just broken.


Perhaps this is the One True Global Scope: the scope in which refs from 
newIORef are guaranteed to be separate.


Every single call to newIORef, across the whole world, returns a different 
ref. The same one as a previous one can only be returned once the old 
one has become unused (and GCed).


It's the scope in which values from newUnique are supposed to be 
different, and it would also be the scope in which top-level - would be 
called at most once.


I don't really follow this. Do you mean the minimal such scope, or the 
maximal such scope? The problem here is not about separate calls to 
newIORef, it's about how many times an individual - will be executed.


Ganesh
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: [Haskell] Top Level -

2008-08-30 Thread Ganesh Sittampalam

On Sat, 30 Aug 2008, Adrian Hey wrote:


Ganesh Sittampalam wrote:
How do the implementers of Data.Unique know that they musn't let them be 
serialised/deserialised?


Because if you could take a String and convert it to a Unique there
would be no guarantee that result was *unique*.


Well, yes, but if I implemented a library in standard Haskell it would 
always be safely serialisable/deserialisable (I think). So the global 
variables hack somehow destroys that property - how do I work out why it 
does in some cases but not others?



I think the whole thread local state thing is a complete red herring.

I've never seen a convincing use case for it and I suspect the only


Well, I've never seen a convincing use case for global variables :-)


reason these to issues have become linked is that some folk are so
convinced that global variables are evil, they mistakenly think
thread local variables must be less evil (because they are less
global).


I don't think they're less evil, just that you might want them for the 
same sorts of reasons you might want global variables.


If plugins breaks is down to plugins to fix itself, at least until such 
time as a suitable formal theory of plugins has been developed so it can 
become standard Haskell :-)


Dynamic loading and plugins work fine with standard Haskell now, because 
nothing in standard Haskell breaks them. The - proposal might well break 
them, which is a significant downside for it. In general, the smaller the 
world that the Haskell standard lives in, the less it can interfere with 
other concerns. - massively increases that world, by introducing the 
concept of a process scope.


It's a hack that isn't robust in many situations. We should find better 
ways to do it, not standardise it.


Nobody's talking about standardising the current hack. This the whole
point of the top level - proposal,


It just amounts to giving the current hack some nicer syntax and stating 
some rules under which it can be used. Those rules aren't actually strong 
enough to provide a guarantee of process level scope.


which JM seems to think is sound enough for incorporation into JHC 
(correctly IMO). Nobody's found fault with it, other than the usual 
global variables are evil mantra :-)


Several people have found faults with it, you've just ignored or dismissed 
them. No doubt from your perspective the faults are irrelevant or untrue, 
but that's not my perspective.


Ganesh
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: [Haskell] Top Level -

2008-08-30 Thread Ganesh Sittampalam

On Sat, 30 Aug 2008, Ashley Yakeley wrote:


Ganesh Sittampalam wrote:
Every single call to newIORef, across the whole world, returns a different 
ref.


How do you know? How can you compare them, except in the same Haskell 
expression?


I can write to one and see if the other changes.

The same one as a previous one can only be returned once the old one has 
become unused (and GCed).


Perhaps, but internally the IORef is a pointer value, and those pointer 
values might be the same. From the same perspective, one could say that


How can they be the same unless the memory management system is broken? I 
consider different pointers on different machines or in different virtual 
address spaces different too; it's the fact that they don't alias 
that matters.


every single call to newUnique across the whole world returns a different 
value, but internally they are Integers that might repeat.


The thing about pointers is that they are managed by the standard 
behaviour of memory allocation. This isn't true of Integers.


In fact this point suggests an implementation for Data.Unique that should 
actually be safe without global variables: just use IORefs for the actual 
Unique values. IORefs already support Eq, as it happens. That gives you 
process scope for free, and if you want bigger scopes you can pair that 
with whatever makes sense, e.g. process ID, MAC address, etc.


Two IO executions are in the same global scope if their resulting 
values can be used in the same expression. Top-level - declarations 
must execute at most once in this scope.


This brings us back to the RPC question, and indeed to just passing values 
to somewhere else via FFI. I think you can work around some of that by 
talking about ADTs that aren't serialisable (e.g. ban the class Storable), 
but now we have different global scopes for different kinds of values, so 
which scope do we use to define - ?


Ganesh
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: [Haskell] Top Level -

2008-08-30 Thread Adrian Hey

Ganesh Sittampalam wrote:

On Sat, 30 Aug 2008, Adrian Hey wrote:

Because if you could take a String and convert it to a Unique there
would be no guarantee that result was *unique*.


Well, yes, but if I implemented a library in standard Haskell it would 
always be safely serialisable/deserialisable (I think). So the global 
variables hack somehow destroys that property - how do I work out why it 
does in some cases but not others?


This has nothing to do with the use of global variables. If you have
a set of values that are guaranteed to be distinct (unique) and you
add another random/arbitrary value to that set you have no way of
knowing that it is different from any current member (other than
searching the entire set, assuming it's available).


Well, I've never seen a convincing use case for global variables :-)


Well apart from all the libs that couldn't be implemented with them...


reason these to issues have become linked is that some folk are so
convinced that global variables are evil, they mistakenly think
thread local variables must be less evil (because they are less
global).


I don't think they're less evil, just that you might want them for the 
same sorts of reasons you might want global variables.


Global variables are needed to ensure important safety properties,
but the only reasons I've seen people give for thread local variables
is that explicit state threading is just so tiresome and ugly. Well
that may be (wouldn't disagree), but I'm not aware of any library
that simply couldn't be implemented without them.

If plugins breaks is down to plugins to fix itself, at least until 
such time as a suitable formal theory of plugins has been developed so 
it can become standard Haskell :-)


Dynamic loading and plugins work fine with standard Haskell now, because 
nothing in standard Haskell breaks them. The - proposal might well 
break them, which is a significant downside for it.


I don't see how, but if so - bindings are not the cause of the
brokeness. They'd still be broken using the unsafePerformIO hack.

In general, the 
smaller the world that the Haskell standard lives in, the less it can 
interfere with other concerns. - massively increases that world, by 
introducing the concept of a process scope.


All IORefs,MVars,Chans scope across the entire process defined by main.
Or at least they *should*, if they don't then something is already
badly wrong somewhere. This has nothing to do with whether or not they
appear at top level. This is what an IORef/MVar whatever is defined to
be.



It's a hack that isn't robust in many situations. We should find 
better ways to do it, not standardise it.


Nobody's talking about standardising the current hack. This the whole
point of the top level - proposal,


It just amounts to giving the current hack some nicer syntax and stating 
some rules under which it can be used.


No, the unsafePerformIO hack is a hack because it's *unsound*. The
compiler doesn't know how to translate this into code that does
what the programmer intended. Fortunately ghc at least does have
a couple of flags that give the intended result (we hope).

The new binding syntax is nicer, but it's real purpose is to leave the
compiler no wriggle room when interpreting the programmers intent.

But then again, I'm sure that some that will be adamant that any way
of making global variables is a hack. But they'll still be happy
to go on using file IO, sockets etc regardless, blissfully unaware
of the hacks they are dependent on :-)

Those rules aren't actually 
strong enough to provide a guarantee of process level scope.


The rules for - bindings shouldn't have to guarantee this.
This should be guaranteed by newMVar returning a new *MVar*, wherever
it's used (for example).

which JM seems to think is sound enough for incorporation into JHC 
(correctly IMO). Nobody's found fault with it, other than the usual 
global variables are evil mantra :-)


Several people have found faults with it, you've just ignored or 
dismissed them. No doubt from your perspective the faults are irrelevant 
or untrue, but that's not my perspective.


I mean semantic faults, as in the proposal just doesn't do what it
promises for some subtle reason. If you consider not giving you thread
local variables a fault I guess you're entitled to that view, but this
was never the intent of the proposal in the first place (that's not
what people are trying to do when they use the unsafePerformIO hack).

Regards
--
Adrian Hey


___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: [Haskell] Top Level -

2008-08-30 Thread Adrian Hey

Adrian Hey wrote:

Global variables are needed to ensure important safety properties,
but the only reasons I've seen people give for thread local variables
is that explicit state threading is just so tiresome and ugly. Well
that may be (wouldn't disagree), but I'm not aware of any library
that simply couldn't be implemented without them.


I thought I ought to say a bit more about my unkind and hasty
words re. thread local variables. This is discussed from time to
time and there's a wiki page here sumarising proposals...

 http://www.haskell.org/haskellwiki/Thread-local_storage

One thing that worries me is that nobody seems to know what problem
thread local storage is solving, hence diversity of proposals. I'm
also a struggling to see why we need it, but I don't have any passionate
objections to it either.

Unfortunately for those of us that want a solution to the global
variables problem the two issues seem have been linked as being the
part of same problem, so while there's all this uncertainty about what
thread local variables are actually going to be used for and what they
should look like the (IMO) much simpler global variables
problem/solution is in limbo. This has been going on 4 or 5 years now
IIRC.

But the global variables problem is really much simpler. All we
want is something that does exactly what the unsafePerformIO hack
currently does (assuming flag/pragma hackery does the trick), but
does it reliably. (IMO, YMMV..)

Regards
--
Adrian Hey

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: [Haskell] Top Level -

2008-08-30 Thread Brandon S. Allbery KF8NH

On 2008 Aug 30, at 6:28, Adrian Hey wrote:

Ganesh Sittampalam wrote:
How do the implementers of Data.Unique know that they musn't let  
them be serialised/deserialised?


Because if you could take a String and convert it to a Unique there
would be no guarantee that result was *unique*.


What stops the same rule from applying to Data.Random?


Well the only data type defined by this is StdGen, which is a Read/ 
Show
instance. I guess there's no semantic problem with that (can't think  
of

one off hand myself).


You *want* to be able to reproduce a given random seed, for  
simulations and the like.


--
brandon s. allbery [solaris,freebsd,perl,pugs,haskell] [EMAIL PROTECTED]
system administrator [openafs,heimdal,too many hats] [EMAIL PROTECTED]
electrical and computer engineering, carnegie mellon universityKF8NH


___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: [Haskell] Top Level -

2008-08-29 Thread Adrian Hey

Brandon S. Allbery KF8NH wrote:


On 2008 Aug 28, at 20:45, Adrian Hey wrote:


Lennart Augustsson wrote:

If Haskell had always taken the pragmatic path of adding what seems
easiest and most in line with imperative practice it would not be the
language it is today.  It would be Perl, ML, or Java.
The Haskell philosophy has always been to stick it out until someone
comes up with the right solution to a problem rather than picking some
easy way out.


BTW, unsafePerformIO seems quite pragmatic and easy to me, so let's
not get too snobby about this. (Sorry, I couldn't resist.)



It's anything but easy; there are specific rules you need to follow, 
including use of certain compiler pragmas, to insure it works properly.


Yes, of course. The worst thing about all this is that the single most
common use case AFAICS (the one under discussion) isn't even a safe
use. Just pointing out that this pseudo function is certainly not
something one would expect from an organisation as dedicated to the
persuit of perfection as Lennart would have us believe. It's an
expedient hack. Not that I wish to seem ungrateful or anything :-)

Regards
--
Adrian Hey

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: [Haskell] Top Level -

2008-08-29 Thread Brandon S. Allbery KF8NH

On 2008 Aug 29, at 4:22, Adrian Hey wrote:

Brandon S. Allbery KF8NH wrote:

On 2008 Aug 28, at 20:45, Adrian Hey wrote:

Lennart Augustsson wrote:

If Haskell had always taken the pragmatic path of adding what seems
easiest and most in line with imperative practice it would not be  
the

language it is today.  It would be Perl, ML, or Java.
The Haskell philosophy has always been to stick it out until  
someone
comes up with the right solution to a problem rather than picking  
some

easy way out.


BTW, unsafePerformIO seems quite pragmatic and easy to me, so let's
not get too snobby about this. (Sorry, I couldn't resist.)
It's anything but easy; there are specific rules you need to  
follow, including use of certain compiler pragmas, to insure it  
works properly.


Yes, of course. The worst thing about all this is that the single most
common use case AFAICS (the one under discussion) isn't even a safe
use. Just pointing out that this pseudo function is certainly not
something one would expect from an organisation as dedicated to the
persuit of perfection as Lennart would have us believe. It's an
expedient hack. Not that I wish to seem ungrateful or anything :-)



...but, as he noted, we *do* that until we find the right way to do it.

--
brandon s. allbery [solaris,freebsd,perl,pugs,haskell] [EMAIL PROTECTED]
system administrator [openafs,heimdal,too many hats] [EMAIL PROTECTED]
electrical and computer engineering, carnegie mellon universityKF8NH


___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: [Haskell] Top Level -

2008-08-29 Thread Adrian Hey

Brandon S. Allbery KF8NH wrote:

On 2008 Aug 29, at 4:22, Adrian Hey wrote:

Brandon S. Allbery KF8NH wrote:

On 2008 Aug 28, at 20:45, Adrian Hey wrote:

Lennart Augustsson wrote:

If Haskell had always taken the pragmatic path of adding what seems
easiest and most in line with imperative practice it would not be the
language it is today.  It would be Perl, ML, or Java.
The Haskell philosophy has always been to stick it out until someone
comes up with the right solution to a problem rather than picking some
easy way out.


BTW, unsafePerformIO seems quite pragmatic and easy to me, so let's
not get too snobby about this. (Sorry, I couldn't resist.)
It's anything but easy; there are specific rules you need to follow, 
including use of certain compiler pragmas, to insure it works properly.


Yes, of course. The worst thing about all this is that the single most
common use case AFAICS (the one under discussion) isn't even a safe
use. Just pointing out that this pseudo function is certainly not
something one would expect from an organisation as dedicated to the
persuit of perfection as Lennart would have us believe. It's an
expedient hack. Not that I wish to seem ungrateful or anything :-)



...but, as he noted, we *do* that until we find the right way to do it.


So what's the problem with doing it *safely*, that is at least until
someone has found the mythic right way to do it.

Not that anybody has ever been able to offer any rational explanation
of what's *wrong* with the current proposed solution AFAICS.

Regards
--
Adrian Hey





___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: [Haskell] Top Level -

2008-08-29 Thread Ganesh Sittampalam

On Thu, 28 Aug 2008, Adrian Hey wrote:


Ganesh Sittampalam wrote:

On Thu, 28 Aug 2008, Adrian Hey wrote:


There's no semantic difficulty with the proposed language extension,


How does it behave in the presence of dynamic loading?


To answer this you need to be precise about the semantics of what
is being dynamically loaded. But this is too complex an issue
for me to get in to right now.


If you want to standardise a language feature, you have to explain its 
behaviour properly. This is one part of the necessary explanation.


To be concrete about scenarios I was considering, what happens if:

 - the same process loads two copies of the GHC RTS as part of two 
completely independent libraries? For added complications, imagine that 
one of the libraries uses a different implementation instead (e.g. Hugs)


 - one Haskell program loads several different plugins in a way that 
allows Haskell values to pass across the plugin boundary


How do these scenarios work with use cases for - like (a) Data.Unique and 
(b) preventing multiple instantiation of a sub-library?


Actually as far as things like hs-plugins are concerned I'd alway meant 
one day what exactly a plugin is, semantically. But as I've never had 
cause to use them so never got round to it. Like is it a value, or does 
it have state and identity or what?


Personally I think of them as values. I'm not sure what your questions 
about state and identity mean. If you don't have global variables, then 
state doesn't matter.



What about remote procedure calls?


Dunno, what problem do you anticipate?


Will Data.Unique still work properly if a value is sent across a RPC 
interface?



Also what if I want a thread-local variable?


Well actually I would say that threads are bad concurrency model so
I'm not keen on thread local state at all. Mainly because I'd like to
get rid of threads, but also a few other doubts even if we keep
threads.


Even if you don't like them, people still use them.

(I.E. Just making existing practice *safe*, at least in the sense that 
the compiler ain't gonna fcuk it up with INLINING or CSE and every one 
understands what is and isn't safe in ACIO)


Creating new language features means defining their semantics rather more 
clearly than just no inlining or cse, IMO.


Ganesh
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: [Haskell] Top Level -

2008-08-29 Thread Dan Weston
C++ faced this very issue by saying that with global data, uniqueness of 
initialization is guaranteed but order of evaluation is not. Assuming 
that the global data are merely thunk wrappers over some common data 
source, this means that at minimum, there can be no data dependencies 
between plugins where the order of evaluation matters.


Another C++ comparison is with a virtual base class, where A::B::D and 
A::C::D are supposed to be equal, irrespective of whether it was B or C 
that first called the constructor. In this case, some witness (a vtable) 
is necessary to ensure that this happens correctly.


Dan

Ganesh Sittampalam wrote:

On Thu, 28 Aug 2008, Adrian Hey wrote:


Ganesh Sittampalam wrote:

On Thu, 28 Aug 2008, Adrian Hey wrote:


There's no semantic difficulty with the proposed language extension,


How does it behave in the presence of dynamic loading?


To answer this you need to be precise about the semantics of what
is being dynamically loaded. But this is too complex an issue
for me to get in to right now.


If you want to standardise a language feature, you have to explain its 
behaviour properly. This is one part of the necessary explanation.


To be concrete about scenarios I was considering, what happens if:

 - the same process loads two copies of the GHC RTS as part of two 
completely independent libraries? For added complications, imagine that 
one of the libraries uses a different implementation instead (e.g. Hugs)


 - one Haskell program loads several different plugins in a way that 
allows Haskell values to pass across the plugin boundary


How do these scenarios work with use cases for - like (a) Data.Unique 
and (b) preventing multiple instantiation of a sub-library?


Actually as far as things like hs-plugins are concerned I'd alway 
meant one day what exactly a plugin is, semantically. But as I've 
never had cause to use them so never got round to it. Like is it a 
value, or does it have state and identity or what?


Personally I think of them as values. I'm not sure what your questions 
about state and identity mean. If you don't have global variables, then 
state doesn't matter.



What about remote procedure calls?


Dunno, what problem do you anticipate?


Will Data.Unique still work properly if a value is sent across a RPC 
interface?



Also what if I want a thread-local variable?


Well actually I would say that threads are bad concurrency model so
I'm not keen on thread local state at all. Mainly because I'd like to
get rid of threads, but also a few other doubts even if we keep
threads.


Even if you don't like them, people still use them.

(I.E. Just making existing practice *safe*, at least in the sense that 
the compiler ain't gonna fcuk it up with INLINING or CSE and every one 
understands what is and isn't safe in ACIO)


Creating new language features means defining their semantics rather 
more clearly than just no inlining or cse, IMO.


Ganesh
___
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


Re: [Haskell-cafe] Re: [Haskell] Top Level -

2008-08-29 Thread Bryan O'Sullivan
On Fri, Aug 29, 2008 at 4:33 PM, Dan Weston [EMAIL PROTECTED] wrote:
 C++ faced this very issue by saying that with global data, uniqueness of
 initialization is guaranteed but order of evaluation is not.

In C++ circles, this is referred to as the static initialization
order fiasco, and it is a frequent cause of crashes that are very
difficult to debug.

http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.12

I think it would be fair to say that C++ pushed this problem off to
every user of the language. I haven't seen a coherent description of
what the semantics of top-level - should be, but avoidance of
widespread swearing would be at the top of my list of requirements.
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: [Haskell] Top Level -

2008-08-29 Thread Dan Weston
I actually was more interested in the problems with the obvious fix 
for this, namely the construct on first use idiom:


int A(int a) { static int aa = a; return aa; }
int B()  { return A(3); }
int C()  { return A(7); }
int D()  { if (today() == Tuesday) B(); else C(); return a(0); }

What is the value of D? Notice that this is never a problem with pure 
functions. The problem is that today() makes this an IO monad, and the 
swearing starts again.


Dan

Bryan O'Sullivan wrote:

On Fri, Aug 29, 2008 at 4:33 PM, Dan Weston [EMAIL PROTECTED] wrote:

C++ faced this very issue by saying that with global data, uniqueness of
initialization is guaranteed but order of evaluation is not.


In C++ circles, this is referred to as the static initialization
order fiasco, and it is a frequent cause of crashes that are very
difficult to debug.

http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.12

I think it would be fair to say that C++ pushed this problem off to
every user of the language. I haven't seen a coherent description of
what the semantics of top-level - should be, but avoidance of
widespread swearing would be at the top of my list of requirements.





___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: [Haskell] Top Level -

2008-08-29 Thread Adrian Hey

Ganesh Sittampalam wrote:
Will Data.Unique still work properly if a value is sent across a RPC 
interface?


A value of type Unique you mean? This isn't possible. Data.Unique has
been designed so cannot be Shown/Read or otherwise
serialised/deserialised (for obvious reasons I guess).


Also what if I want a thread-local variable?


Well actually I would say that threads are bad concurrency model so
I'm not keen on thread local state at all. Mainly because I'd like to
get rid of threads, but also a few other doubts even if we keep
threads.


Even if you don't like them, people still use them.


AFAICS this is irrelvant for the present discussions as Haskell doesn't
support thread local variable thingies. If it ever does being precise
about that is someone elses problem. For the time being the scope
of IORefs/MVars/Chans is (and should remain) whatever process is
described by main (whether or not they appear at top level).

(I.E. Just making existing practice *safe*, at least in the sense that 
the compiler ain't gonna fcuk it up with INLINING or CSE and every one 
understands what is and isn't safe in ACIO)


Creating new language features means defining their semantics rather 
more clearly than just no inlining or cse, IMO.


I wouldn't even know how to go about that to the satisfaction of
purists. But global variables *are* being used whether or not the top
level - bindings are implemented. They're in the standard libraries!

So if this stuff matters someone had better figure it out :-)

Regards
--
Adrian Hey

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: [Haskell] Top Level -

2008-08-29 Thread Adrian Hey

Bryan O'Sullivan wrote:

I haven't seen a coherent description of
what the semantics of top-level - should be, but avoidance of
widespread swearing would be at the top of my list of requirements.


Don't the ACIO monad properties satisfy you?

Anyway, as I pointed out in my last post, if this is a problem
with top level - ACIO monad bindings it's still going to be
a problem (probably much worse) with unsafePerformIO hack IO
monad bindings.

This problem isn't just going to go away, no matter how long
it's ignored :-)

Regards
--
Adrian Hey

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: [Haskell] Top Level -

2008-08-28 Thread Lennart Augustsson
I'm certain you can write a kernel in Haskell where the only use of
global variables is those that hardware interfacing forces you to use.

On Thu, Aug 28, 2008 at 3:32 AM, John Meacham [EMAIL PROTECTED] wrote:
 On Thu, Aug 28, 2008 at 12:15:10AM +0100, Lennart Augustsson wrote:
 I didn't say NetBSD doesn't use global variables, I said the device
 driver model doesn't use global variables.  And quite a few things
 that used to be in global variables have been moved into allocated
 variables and are being passed around instead.  That's simply a better
 way to structure the code.

 Indeed. I have experimented with single address space operating systems where
 it is pretty much the only way to do things at the user level. But I
 still want to be able to implement my kernel in haskell. :)


 I don't don't think global variables should be banned, I just think
 they should be severly discouraged.

 Oh, I certainly agree with that. especially among new programmers. I
 think ACIO is a particularly elegant way to provide them in haskell for
 when they are needed. Every time I can avoid resorting to C code for a
 task without sacrificing performance, aethetics, or correctness, it is a
 good day.

John



 --
 John Meacham - ⑆repetae.net⑆john⑈
 ___
 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


Re: [Haskell-cafe] Re: [Haskell] Top Level -

2008-08-28 Thread Adrian Hey

Jonathan Cast wrote:

On Wed, 2008-08-27 at 11:53 +0100, Adrian Hey wrote:

John Meacham wrote:

As with all design decisions, it is sometimes the right thing and
sometimes the wrong one. And sometimes the most expedient. (which,
occasionally, is a perfectly valid driving force behind a certain bit of
coding). However, I am fully convinced it is necessary. You don't even
have to look further than Haskell 98 to find a use in the Random module,
and Data.Unique _depends_ on the state being global for correctness.

..and of course there's stdin, stdout. That takes some explaining.


Not really.  If you don't have buffered IO, then you just say

stdin = 0
stdout = 1
stderr = 2


nonStdout = 42?

I'm afraid I have no idea what your point is :-(

I tried it anyway and doesn't seem to work, but that ain't so surprising
as Handles aren't Nums.

What needs explaining IMO is that we appear to have global Handles
exported at the top level from System.IO, but no way for users to write
their own modules that do the same for nonStdout, or even to implement
getNonStdout. I think that's pretty weird and inconsistent.

But perhaps you could show me how to do it with some real Haskell :-)


If you need buffered IO, you just change your IO monad* to look like:

newtype NewIO alpha = NewIO (ReaderT (Map Fd Buffer) OldIO alpha)

Of course, if you do this, you can't go mixing IO with unique values
with RNG with mutable state with everything else under the sun anymore.
You might actually have to declare exactly what effects you need when
you give your function's type, now.  Clearly, a horror we must avoid at
all costs.


Indeed. If anyone thinks that's the way to go maybe Clean would be of
some interest. IMHO Cleans treatment of IO and concurrency is just about
the worst thing in an otherwise pretty decent language :-(

Regards
--
Adrian Hey


___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: [Haskell] Top Level -

2008-08-28 Thread Adrian Hey

Lennart Augustsson wrote:
 I don't don't think global variables should be banned, I just think
 they should be severly discouraged.

If you're saying a language should not provide a sound way to do
this (as I believe you are), then AFAICT for all practical purposes
you *are* saying you think global variables should be banned.

Where are we going to be if the unsafePerformIO hack ever becomes
*really* unsafe?

and..


I'm certain you can write a kernel in Haskell where the only use of
global variables is those that hardware interfacing forces you to use.


But what you haven't explained is why this is even desirable? I don't
doubt it's true in an academic sense if you don't mind sacrificing
safety and modularity. Why wasn't this done in the (presumably) much
simpler case of the Haskell base libs? No hardware constraints there.

There are plenty situations where it makes no semantic sense to allow
2 or more or some thing. A list of all active processes for example.

Why would I ever want 2 or more lists of all active processes? I think
I'd just be setting myself up for trouble and heartache by even allowing
such a possibility.

Now I could get the safety I need by wrapping all this stuff up in my
own custom augmented IO monad right at the start of main. But this
solution still lacks modularity. The top level - bindings are just
a modular and extensible way to achieve the same thing AFAICS
(augmenting real world state with my own custom state).

Regards
--
Adrian Hey
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: [Haskell] Top Level -

2008-08-28 Thread Johannes Waldmann
Adrian Hey wrote:

 There are plenty situations where it makes no semantic sense to allow
 2 or more or some thing. A list of all active processes for example.

all referring to what scope? perhaps there occurs a situation
with several process (thread) pools, severals cores etc.

See also singleton considered harmful, there are similar arguments:
http://www.oreillynet.com/cs/user/view/cs_msg/23417

and also Section 13.3 Global Data
in McConnell: Code Complete (2nd ed.) has a nice discussion.

J.W.



signature.asc
Description: OpenPGP digital signature
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: [Haskell] Top Level -

2008-08-28 Thread Adrian Hey

Johannes Waldmann wrote:

Adrian Hey wrote:


There are plenty situations where it makes no semantic sense to allow
2 or more or some thing. A list of all active processes for example.


all referring to what scope? perhaps there occurs a situation
with several process (thread) pools, severals cores etc.


Seeing as we're talking about an OS kernel I guess the scope would
be all processes active on the (possibly virtual) machine being
managed by the OS.

But it really doesn't matter what the scope is. All is the key
word here.


See also singleton considered harmful, there are similar arguments:
http://www.oreillynet.com/cs/user/view/cs_msg/23417


Following the arguments made against the singleton pattern over the
years leads me to conclude there are 2 distinct camps.

Applications programmers who consider it bad because it's way of
making global variables and we all know how bad they are, right?
Typically these folk appear to have no clue about how the underlying
IO library, framework and OS infrastructure they are dependent on
*actually works*.

System programmers who recognise the need for singletons but regard
being forced to use the singleton pattern hack as language design
defect.

The situation seems similar with us. The unsafePerformIO hack is
just terrible (especially for a language like Haskell), but why
is it being used so often? Is it incompetance of library writers
or a language design defect?

Regards
--
Adrian Hey


___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: [Haskell] Top Level -

2008-08-28 Thread Jonathan Cast
On Thu, 2008-08-28 at 10:00 +0100, Adrian Hey wrote:
 Lennart Augustsson wrote:
   I don't don't think global variables should be banned, I just think
   they should be severly discouraged.
 
 If you're saying a language should not provide a sound way to do
 this (as I believe you are), then AFAICT for all practical purposes
 you *are* saying you think global variables should be banned.
 
 Where are we going to be if the unsafePerformIO hack ever becomes
 *really* unsafe?
 
 and..
 
  I'm certain you can write a kernel in Haskell where the only use of
  global variables is those that hardware interfacing forces you to use.
 
 But what you haven't explained is why this is even desirable? I don't
 doubt it's true in an academic sense if you don't mind sacrificing
 safety 

What `safety' is being sacrificed?

 and modularity.

What modularity?

jcc


___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: [Haskell] Top Level -

2008-08-28 Thread Adrian Hey

Jonathan Cast wrote:

On Thu, 2008-08-28 at 10:00 +0100, Adrian Hey wrote:

Lennart Augustsson wrote:
  I don't don't think global variables should be banned, I just think
  they should be severly discouraged.

If you're saying a language should not provide a sound way to do
this (as I believe you are), then AFAICT for all practical purposes
you *are* saying you think global variables should be banned.

Where are we going to be if the unsafePerformIO hack ever becomes
*really* unsafe?

and..


I'm certain you can write a kernel in Haskell where the only use of
global variables is those that hardware interfacing forces you to use.

But what you haven't explained is why this is even desirable? I don't
doubt it's true in an academic sense if you don't mind sacrificing
safety 


What `safety' is being sacrificed?


and modularity.


What modularity?


As I've pointed out several times already you can find simple examples
in the standard haskell libs. So far nobody has accepted my challenge to
re-implement any of these competantly (I.E. avoiding the use of global
variables).

Why don't you try it with Data.Unique and find out :-)

Regards
--
Adrian Hey

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: [Haskell] Top Level -

2008-08-28 Thread Dan Doel
On Thursday 28 August 2008 12:26:27 pm Adrian Hey wrote:
 As I've pointed out several times already you can find simple examples
 in the standard haskell libs. So far nobody has accepted my challenge to
 re-implement any of these competantly (I.E. avoiding the use of global
 variables).

 Why don't you try it with Data.Unique and find out :-)

Here's a first pass:

-- snip --

{-# LANGUAGE Rank2Types, GeneralizedNewtypeDeriving #-}

module Unique where

import Control.Monad.Reader
import Control.Monad.Trans

import Control.Concurrent.MVar

-- Give Uniques a phantom region parameter, so that you can't accidentally
-- compare Uniques from two different uniqueness sources.
newtype Unique r = Unique Integer deriving Eq

newtype U r a = U { unU :: ReaderT (MVar Integer) IO a }
  deriving (Functor, Monad, MonadIO)

-- Higher rank type for region consistency
runU :: (forall r. U r a) - IO a
runU m = newMVar 0 = runReaderT (unU m)

newUnique :: U r (Unique r)
newUnique = U (do source - ask
  val - lift $ takeMVar source
  let next = val + 1
  lift $ putMVar source next
  return $ Unique next)

-- hashUnique omitted

-- snip --

It's possible that multiple unique sources can exist in a program with this 
implementation, but because of the region parameter, the fact that a Unique 
may not be globally unique shouldn't be a problem. If your whole program 
needs arbitrary access to unique values, then I suppose something like:

main = runU realMain

realMain :: U r ()
realMain = ...

is in order.

Insert standard complaints about this implementation requiring liftIO all over 
the place if you actually want to do other I/O stuff inside the U monad.

You could also make a version that extracts to STM, or even a pure version if 
you don't need unique values across multiple threads.

-- Dan
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: [Haskell] Top Level -

2008-08-28 Thread Lennart Augustsson
I don't think anyone has claimed that any interface can be implemented
without globals.
Of course some can't (just pick an interface that is the specification
of a global variable).

What I (and others) claims is that such interfaces are bad.  Using a
global variable makes an assumption that there's only ever going to be
one of something, and that's just an inflexible assumption to make.

You think global variables are essential, I think they are a sign of
bad design.  So we have different opinions and neither one of us is
going to convince the other.

I think a lot of things related to the IO monad in Haskell is bad
design; influenced by imperative thinking.

For instance, I think the main function should have a type like
  main :: (IOMonad io) = io a
where IOMonad contains some basic functionality like calling C.
Then you could do things like implement runInsandboxIO which traces all C calls.

  -- Lennart

On Thu, Aug 28, 2008 at 5:26 PM, Adrian Hey [EMAIL PROTECTED] wrote:
 Jonathan Cast wrote:

 On Thu, 2008-08-28 at 10:00 +0100, Adrian Hey wrote:

 Lennart Augustsson wrote:
   I don't don't think global variables should be banned, I just think
   they should be severly discouraged.

 If you're saying a language should not provide a sound way to do
 this (as I believe you are), then AFAICT for all practical purposes
 you *are* saying you think global variables should be banned.

 Where are we going to be if the unsafePerformIO hack ever becomes
 *really* unsafe?

 and..

 I'm certain you can write a kernel in Haskell where the only use of
 global variables is those that hardware interfacing forces you to use.

 But what you haven't explained is why this is even desirable? I don't
 doubt it's true in an academic sense if you don't mind sacrificing
 safety

 What `safety' is being sacrificed?

 and modularity.

 What modularity?

 As I've pointed out several times already you can find simple examples
 in the standard haskell libs. So far nobody has accepted my challenge to
 re-implement any of these competantly (I.E. avoiding the use of global
 variables).

 Why don't you try it with Data.Unique and find out :-)

 Regards
 --
 Adrian Hey

 ___
 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


Re: [Haskell-cafe] Re: [Haskell] Top Level -

2008-08-28 Thread David Roundy
On Thu, Aug 28, 2008 at 01:17:29PM -0400, Dan Doel wrote:
 On Thursday 28 August 2008 12:26:27 pm Adrian Hey wrote:
  As I've pointed out several times already you can find simple examples
  in the standard haskell libs. So far nobody has accepted my challenge to
  re-implement any of these competantly (I.E. avoiding the use of global
  variables).
 
  Why don't you try it with Data.Unique and find out :-)
 
 Here's a first pass:
 
 -- snip --
 
 {-# LANGUAGE Rank2Types, GeneralizedNewtypeDeriving #-}
 
 module Unique where

If you want this to actually provide any guarantees, of course, you'll
have to provide an export list.

David
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: [Haskell] Top Level -

2008-08-28 Thread Adrian Hey

Lennart Augustsson wrote:

I don't think anyone has claimed that any interface can be implemented
without globals.
Of course some can't (just pick an interface that is the specification
of a global variable).


I said in the original challenge even I'd let you (anyone) change the
interface if you could provide a sensible explanation of why the
new interface was better, safer, more convenient or whatever.


What I (and others) claims is that such interfaces are bad.  Using a
global variable makes an assumption that there's only ever going to be
one of something,


It's not an assumption, any more than I always want 1*N to yield N is
an assumption.

It's a fundamental property I absolutely want to guarantee. By far the
simplest way to do this is simply not to expose a newWhatever
constructor in my API. If I expose anything it should be Whatever itself
or getWatever, neither of which is possible if Whatever contains MVars,
Chans and the like.

What's more, there seems to be no good *semantic* reason why this should
not be possible. The only objections seem dogmatic to me.


and that's just an inflexible assumption to make.

You think global variables are essential, I think they are a sign of
bad design.  So we have different opinions and neither one of us is
going to convince the other.


You might stand some chance of convincing me by showing a better
design :-)

Dan seems to have had a reasonable go at 1 of them. I'm not sure
passes the improved interface test but I'll think about it. But
there are quite a few left.

There's the Hughes paper too of course, using implicit parameters
(a highly dubious language feature IMO).

But even if someone does produce an entirely unsafePerformIO hack
free set of standard libs, I have to ask why jump through all these
hoops? There's no semantic difficulty with the proposed language
extension, and it should be very simple to implement (John seems
to have done it already).

Regards
--
Adrian Hey

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: [Haskell] Top Level -

2008-08-28 Thread Ganesh Sittampalam

On Thu, 28 Aug 2008, Adrian Hey wrote:


implicit parameters (a highly dubious language feature IMO).


How can you say that with a straight face at the same time as advocating 
global variables? :-)


Ganesh
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: [Haskell] Top Level -

2008-08-28 Thread Ganesh Sittampalam

On Thu, 28 Aug 2008, Adrian Hey wrote:


There's no semantic difficulty with the proposed language extension,


How does it behave in the presence of dynamic loading? What about remote 
procedure calls?


Also what if I want a thread-local variable? It seems like an extension 
like this should also support that, and perhaps other scopes as Duncan 
suggested; why is the process scope special?


Ganesh
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: [Haskell] Top Level -

2008-08-28 Thread John Meacham
On Thu, Aug 28, 2008 at 09:00:41AM +0100, Lennart Augustsson wrote:
 I'm certain you can write a kernel in Haskell where the only use of
 global variables is those that hardware interfacing forces you to use.

And hence you need a safe way to use program-scope variables. It is true that
there are many many programs that can be written without them. But those
don't concern us, if there are _any_ programs that need them that we
wish to write in haskell then we need a safe way in haskell to use them.

The truth is, 'process scope' is a useful scope to attach information
too. Many operating systems attach various resources to process scope,
memory allocation, file descriptors, protection domains. this in and of
itself makes it useful for any programs on these operating systems to be
able to augment this process scope.

I mean, why is it okay to use 'process scope' state provided by the
operating system or haskell runtime, but _not_ be able to express such
things in haskell itself? I mean, lets look at the items provided for by
plain haskell 98 which involve entities that are process scope or bigger:

getStdGen, setStdGen, getEnv, getArgs, stdin,stdout,stderr, cpuTimePrecision, 
isEOF,
getCurrentDirectory, setCurrentDirectory, system, exitWith, exitFailure,
getProgName, getClockTime, probably others in more subtle ways.

do we really want to say that these are all wrong or _must_ be provided
by C or the operating system because implementing them in haskell would
somehow be unclean? Why shouldn't we be able to implement the concept of
a 'current directory' in haskell when we are perfectly happy to use the
OS provided one? What if you have an exokernel, where it is expected
these things _will_ be implemented in the userspace code. why shouldn't
that part of the exokernel be written in haskell?

John


-- 
John Meacham - ⑆repetae.net⑆john⑈
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: [Haskell] Top Level -

2008-08-28 Thread Adrian Hey

Ganesh Sittampalam wrote:

On Thu, 28 Aug 2008, Adrian Hey wrote:


implicit parameters (a highly dubious language feature IMO).


How can you say that with a straight face at the same time as advocating 
global variables? :-)


Quite easily, what's the problem? IORefs, Chans etc are perfectly
ordinary values. Why should they not exist at the top level?

The global variable lives in the world, not the IORef. The
IORef is just a reference, no different from filepaths in principle
(and if having them at the top level is also evil then making this
so easy and not screaming about it seems a little inconsistent to me).

Regards
--
Adrian Hey








___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: [Haskell] Top Level -

2008-08-28 Thread Adrian Hey

Jonathan Cast wrote:

This has been answered repeatedly, at least implicitly.  Unless you
insist that getWhatever should live in the IO monad and have no
functional arguments (why?), there is no reason why this should be
impossible.


What's more, there seems to be no good *semantic* reason why this should
not be possible. The only objections seem dogmatic to me.


I haven't seen you give a non-dogmatic reason for wanting global
variables yet, either.


You consider real examples from real *standard* libs that we're all 
using (and presumably not written by clueless hackers such as myself)

to be dogmatic? I would call that pragmatic myself. These are the
standard libs after all. Shouldn't we expect them to be the perfect
examples of how to do things rite?


But even if someone does produce an entirely unsafePerformIO hack
free set of standard libs, I have to ask why jump through all these
hoops?


To improve the APIs available?


There's nothing wrong with the APIs as they are as far as I am
concerned. It's their implemenation that's the problem.


 You're advocating an extension to a
*purely functional programming language*.


So? What's being proposed doesn't compromise referential transparency
(at least no more that the IO monad already does, as some might argue).


There's no semantic difficulty with the proposed language
extension,


Although I've noticed it's grossly under-powered compared to what's
needed to implement stdin the way you want to.


Can't recall expressing any opinion about how stdin should be
implemented so I don't know what your on about here.

Regards
--
Adrian Hey







___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: [Haskell] Top Level -

2008-08-28 Thread Jonathan Cast
On Thu, 2008-08-28 at 22:24 +0100, Adrian Hey wrote:
 Jonathan Cast wrote:
  This has been answered repeatedly, at least implicitly.  Unless you
  insist that getWhatever should live in the IO monad and have no
  functional arguments (why?), there is no reason why this should be
  impossible.
  
  What's more, there seems to be no good *semantic* reason why this should
  not be possible. The only objections seem dogmatic to me.
  
  I haven't seen you give a non-dogmatic reason for wanting global
  variables yet, either.
 
 You consider real examples from real *standard* libs that we're all 
 using (and presumably not written by clueless hackers such as myself)
 to be dogmatic?

Yeah.  Same as if the examples were APIs from ML, or Lisp.  The neat
thing about Haskell is *precisely* that the ML I/O system has an API
that is illegal in Haskell.  I see no reason, in principle, why the
Haskell standard libraries shouldn't contain APIs that should be illegal
in new-and-improved Future Haskell.

 I would call that pragmatic myself. These are the
 standard libs after all. Shouldn't we expect them to be the perfect
 examples of how to do things rite?
 
  But even if someone does produce an entirely unsafePerformIO hack
  free set of standard libs, I have to ask why jump through all these
  hoops?
  
  To improve the APIs available?
 
 There's nothing wrong with the APIs as they are as far as I am
 concerned.

Right.  That's exactly what we're arguing about.  We maintain they are
inferior.  You haven't really given any defense of them at all, other
than their existence.  I consider that a rather weak argument.

  It's their implemenation that's the problem.
 
   You're advocating an extension to a
  *purely functional programming language*.
 
 So? What's being proposed doesn't compromise referential transparency
 (at least no more that the IO monad already does, as some might argue).

What's a referential transparency?  I just want a language completely
specified by its denotational semantics, in the obvious fashion (e.g.,
(-) maps to an exponential in a real category).

If IO compromises that (heck, who am I kidding, *since* IO compromises
that), I'm arguing we get rid of whatever features it has that are
questionable.

  There's no semantic difficulty with the proposed language
  extension,
  
  Although I've noticed it's grossly under-powered compared to what's
  needed to implement stdin the way you want to.
 
 Can't recall expressing any opinion about how stdin should be
 implemented so I don't know what your on about here.

Well, you didn't like *my* implementation.  You seem to be rather keen
on the current implementation GHC happens to use, where stdin contains
internally a mutable buffer.  You also seem to be rather insistent that,
whatever mechanism GHC uses to get that mutable buffer, be useable to
create *any other top-level handle* I want.  Now, I happen to know that
the only top-level handles that can be established without issuing an
open system call are

stdin
stdout
stderr

(unless you're happy to have your global nonStdErr start its life
attached to an unopened FD).  I really don't see what your point is,
unless you want to be able to `call open at the top level'.

On Thu, 2008-08-28 at 22:01 +0100, Adrian Hey wrote: 
 Ganesh Sittampalam wrote:
  On Thu, 28 Aug 2008, Adrian Hey wrote:
  
  implicit parameters (a highly dubious language feature IMO).
  
  How can you say that with a straight face at the same time as advocating 
  global variables? :-)
 
 Quite easily, what's the problem? IORefs, Chans etc are perfectly
 ordinary values. Why should they not exist at the top level?

They aren't the denotations of any closed Haskell expressions.  Scarcely
`perfectly ordinary'.

 The global variable lives in the world, not the IORef. The
 IORef is just a reference, no different from filepaths in principle

You didn't like my implementation of stdout along those lines, though...

 (and if having them at the top level is also evil then making this
 so easy and not screaming about it seems a little inconsistent to me).

Good point.  We don't just pretend that filepaths make sense in
themselves, independently of context.  (Or would you like to tell me
what the contents of
~/src/globalscript-0.0.1/Language/GlobalScript/Syntax.lhs are?)  In
fact, this mailing list is dedicated to a language that has the radical
idea that you should have to use a whole different type (built using
this scary category-theoretical concept called a `monad') just to
associate filepaths with file contents. 

jcc


___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: [Haskell] Top Level -

2008-08-28 Thread Jonathan Cast
On Thu, 2008-08-28 at 14:45 -0700, Jonathan Cast wrote:
 On Thu, 2008-08-28 at 22:24 +0100, Adrian Hey wrote:
  Jonathan Cast wrote:
   This has been answered repeatedly, at least implicitly.  Unless you
   insist that getWhatever should live in the IO monad and have no
   functional arguments (why?), there is no reason why this should be
   impossible.
   
   What's more, there seems to be no good *semantic* reason why this should
   not be possible. The only objections seem dogmatic to me.
   
   I haven't seen you give a non-dogmatic reason for wanting global
   variables yet, either.
  
  You consider real examples from real *standard* libs that we're all 
  using (and presumably not written by clueless hackers such as myself)
  to be dogmatic?
 
 Yeah.  Same as if the examples were APIs from ML, or Lisp.  The neat
 thing about Haskell is *precisely* that the ML I/O system has an API
 that is illegal in Haskell.  I see no reason, in principle, why the
 Haskell standard libraries shouldn't contain APIs that should be illegal
 in new-and-improved Future Haskell.
 
  I would call that pragmatic myself. These are the
  standard libs after all. Shouldn't we expect them to be the perfect
  examples of how to do things rite?
  
   But even if someone does produce an entirely unsafePerformIO hack
   free set of standard libs, I have to ask why jump through all these
   hoops?
   
   To improve the APIs available?
  
  There's nothing wrong with the APIs as they are as far as I am
  concerned.
 
 Right.  That's exactly what we're arguing about.  We maintain they are
 inferior.  You haven't really given any defense of them at all, other
 than their existence.  I consider that a rather weak argument.
 
   It's their implemenation that's the problem.
  
You're advocating an extension to a
   *purely functional programming language*.
  
  So? What's being proposed doesn't compromise referential transparency
  (at least no more that the IO monad already does, as some might argue).
 
 What's a referential transparency?  I just want a language completely
 specified by its denotational semantics, in the obvious fashion (e.g.,
 (-) maps to an exponential in a real category).
 
 If IO compromises that (heck, who am I kidding, *since* IO compromises
 that), I'm arguing we get rid of whatever features it has that are
 questionable.
 
   There's no semantic difficulty with the proposed language
   extension,
   
   Although I've noticed it's grossly under-powered compared to what's
   needed to implement stdin the way you want to.
  
  Can't recall expressing any opinion about how stdin should be
  implemented so I don't know what your on about here.
 
 Well, you didn't like *my* implementation.  You seem to be rather keen
 on the current implementation GHC happens to use, where stdin contains
 internally a mutable buffer.  You also seem to be rather insistent that,
 whatever mechanism GHC uses to get that mutable buffer, be useable to
 create *any other top-level handle* I want.  Now, I happen to know that
 the only top-level handles that can be established without issuing an
 open system call are
 
 stdin
 stdout
 stderr
 
 (unless you're happy to have your global nonStdErr start its life
 attached to an unopened FD).  I really don't see what your point is,
 unless you want to be able to `call open at the top level'.
 
 On Thu, 2008-08-28 at 22:01 +0100, Adrian Hey wrote: 
  Ganesh Sittampalam wrote:
   On Thu, 28 Aug 2008, Adrian Hey wrote:
   
   implicit parameters (a highly dubious language feature IMO).
   
   How can you say that with a straight face at the same time as advocating 
   global variables? :-)
  
  Quite easily, what's the problem? IORefs, Chans etc are perfectly
  ordinary values. Why should they not exist at the top level?
 
 They aren't the denotations of any closed Haskell expressions.  Scarcely
 `perfectly ordinary'.
 
  The global variable lives in the world, not the IORef. The
  IORef is just a reference, no different from filepaths in principle
 
 You didn't like my implementation of stdout along those lines, though...
 
  (and if having them at the top level is also evil then making this
  so easy and not screaming about it seems a little inconsistent to me).
 
 Good point.  We don't just pretend that filepaths make sense in
 themselves, independently of context.  (Or would you like to tell me
 what the contents of
 ~/src/globalscript-0.0.1/Language/GlobalScript/Syntax.lhs are?)  In
 fact, this mailing list is dedicated to a language that has the radical
 idea that you should have to use a whole different type (built using
 this scary category-theoretical concept called a `monad') just to
 associate filepaths with file contents. 

All true.  But nevertheless reading it over I think I need to step away
from this and cool down a little.

jcc


___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org

Re: [Haskell-cafe] Re: [Haskell] Top Level -

2008-08-28 Thread Yitzchak Gale
Lennart Augustsson wrote:
 I don't think anyone has claimed that any interface can be implemented
 without globals.
 Of course some can't (just pick an interface that is the specification
 of a global variable).
 What I (and others) claims is that such interfaces are bad.  Using a
 global variable makes an assumption that there's only ever going to be
 one of something, and that's just an inflexible assumption to make.

Not true, it's an idiom that comes up often enough.

The right way to do these kinds of things is to provide
some sort of context around the calling function.
Something like withAcquiredResource $ \handle - do ...
You (and others) are right that this is better than trying to
keep global state in the context of the called function.

The problem is that it is not always possible. There are
situations in which you simply cannot make demands
on a prior context. One important example is when
refactoring a single component within an existing mature
system. Another is when writing a library for general use
if such demands on the calling context seem onerous
for the service that the library provides (this latter is the
situation for Data.Unique, according to many opinions).

I find that Haskell's composability properties help it to
outshine any other development environment I know.
Experience shows that this is eventually true even for IO
related issues - but those generally take a lot more work
to discover the right approach. I feel that here we are
still working on tackling the awkward squad.

However we work that out, right now we need a working
idiom to get out of trouble when this situation comes up.
What we have is a hack that is not guaranteed to work.
We are abusing the NOINLINE pragma and assuming
things about it that are not part of its intended use.
We are lucky that it happens to work right now in GHC.

So my proposal is that, right now, we make the simple
temporary fix of adding an ONLYONCE pragma that does
have the proper guaranteed sematics.

In the meantime, we can keep tackling the awkward squad.

Thanks,
Yitz
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: [Haskell] Top Level -

2008-08-28 Thread Adrian Hey

Ganesh Sittampalam wrote:

On Thu, 28 Aug 2008, Adrian Hey wrote:


There's no semantic difficulty with the proposed language extension,


How does it behave in the presence of dynamic loading?


To answer this you need to be precise about the semantics of what
is being dynamically loaded. But this is too complex an issue
for me to get in to right now. Actually as far as things like
hs-plugins are concerned I'd alway meant one day what exactly
a plugin is, semantically. But as I've never had cause to use
them so never got round to it. Like is it a value, or does it
have state and identity or what?


What about remote procedure calls?


Dunno, what problem do you anticipate?


Also what if I want a thread-local variable?


Well actually I would say that threads are bad concurrency model so
I'm not keen on thread local state at all. Mainly because I'd like to
get rid of threads, but also a few other doubts even if we keep
threads.

Yes, I'm no big fan of the IO monad (or any other monad in fact) and
IORefs and all that (all smacks of putting a purely function veneer on
good ol fashioned procedural programming to me). But we are where we are
and this isn't going to change any time soon. Just trying to fix what
seem like obvious problems with Haskells current IO without doing
anything too radical and unproven. (I.E. Just making existing practice
*safe*, at least in the sense that the compiler ain't gonna fcuk it up
with INLINING or CSE and every one understands what is and isn't safe
in ACIO)

Regards
--
Adrian Hey


___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: [Haskell] Top Level -

2008-08-28 Thread Lennart Augustsson
As I said earlier, global variables may be necessary when interfacing
with legacy things (software or hardware).

If Haskell had always taken the pragmatic path of adding what seems
easiest and most in line with imperative practice it would not be the
language it is today.  It would be Perl, ML, or Java.
The Haskell philosophy has always been to stick it out until someone
comes up with the right solution to a problem rather than picking some
easy way out.  So I'd rather keep global variables being eye sores (as
they are now) to remind us to keep looking for a nice way.
For people who don't like this philosophy there are plenty of other languages.

And this concludes my contributions on this matter. :)

  -- Lennart

On Thu, Aug 28, 2008 at 11:06 PM, Yitzchak Gale [EMAIL PROTECTED] wrote:
 The right way to do these kinds of things is to provide
 some sort of context around the calling function.
 Something like withAcquiredResource $ \handle - do ...
 You (and others) are right that this is better than trying to
 keep global state in the context of the called function.

 The problem is that it is not always possible. There are
 situations in which you simply cannot make demands
 on a prior context. One important example is when
 refactoring a single component within an existing mature
 system. Another is when writing a library for general use
 if such demands on the calling context seem onerous
 for the service that the library provides (this latter is the
 situation for Data.Unique, according to many opinions).
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: [Haskell] Top Level -

2008-08-28 Thread Brandon S. Allbery KF8NH

On 2008 Aug 28, at 17:01, John Meacham wrote:

On Thu, Aug 28, 2008 at 09:00:41AM +0100, Lennart Augustsson wrote:

I'm certain you can write a kernel in Haskell where the only use of
global variables is those that hardware interfacing forces you to  
use.


OS provided one? What if you have an exokernel, where it is expected
these things _will_ be implemented in the userspace code. why  
shouldn't

that part of the exokernel be written in haskell?



What's stopping it?  Just wrap it in a state-carrying monad  
representing a context.  That way you can also keep multiple contexts  
if necessary (and I think it is often necessary, or at least  
desirable, with most exokernel clients).


--
brandon s. allbery [solaris,freebsd,perl,pugs,haskell] [EMAIL PROTECTED]
system administrator [openafs,heimdal,too many hats] [EMAIL PROTECTED]
electrical and computer engineering, carnegie mellon universityKF8NH


___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: [Haskell] Top Level -

2008-08-28 Thread Yitzchak Gale
Lennart Augustsson wrote:
 As I said earlier, global variables may be necessary when interfacing
 with legacy things (software or hardware).

By prior context I didn't mean legacy languages. I meant
logically prior - enclosing contexts.

It will always be necessary on occasion to refactor code
without having any access to the enclosing context.
If that refactoring happens to include acquiring an external
resource once, using it while our program is running, and
releasing it at the end, it is currently an awkward situation
for us. We're working on finding a fitting solution to this.

 The Haskell philosophy has always been to stick it out until someone
 comes up with the right solution to a problem rather than picking some
 easy way out.  So I'd rather keep global variables being eye sores (as
 they are now) to remind us to keep looking for a nice way.

I agree. But the eyesores do need to be guaranteed to work.
That is not currently the case. It's easy to fix the eyesores,
so I think we should do that now.

Regards,
Yitz
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: [Haskell] Top Level -

2008-08-28 Thread Philippa Cowderoy
On Thu, 2008-08-28 at 23:48 +0100, Lennart Augustsson wrote:
 The Haskell philosophy has always been to stick it out until someone
 comes up with the right solution to a problem rather than picking some
 easy way out.  So I'd rather keep global variables being eye sores (as
 they are now) to remind us to keep looking for a nice way.
 For people who don't like this philosophy there are plenty of other languages.

Talking of which, we really ought to look at an IO typeclass or two (not
just our existing MonadIO) and rework the library ops to use it in
Haskell'. You're not the only one to want it, and if it's not fixed this
time it may never get fixed.


-- 
Philippa Cowderoy [EMAIL PROTECTED]

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: [Haskell] Top Level -

2008-08-28 Thread Adrian Hey

Lennart Augustsson wrote:

The Haskell philosophy has always been to stick it out until someone
comes up with the right solution to a problem rather than picking some
easy way out.


I understood from your previous remarks that you regarded this as a
non-problem even in C. There's no justification for using them, at
least if you have clean slate priveleges (no legacy issues).

That kind of implies to me that we (or at least you) already have the
right solution. What is it and why can't we use it right now in Haskell?
(Again assuming we have clean slate and no legacy issues). Or can we..


So I'd rather keep global variables being eye sores (as
they are now) to remind us to keep looking for a nice way.


Are you looking? I can't even figure out from your posts if you're even
prepared to admit that there *is* a problem, other than there being so
many people in the world who can't write proper code, in Haskell or C
:-)

Regards
--
Adrian Hey

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: [Haskell] Top Level -

2008-08-28 Thread Adrian Hey

Lennart Augustsson wrote:

If Haskell had always taken the pragmatic path of adding what seems
easiest and most in line with imperative practice it would not be the
language it is today.  It would be Perl, ML, or Java.
The Haskell philosophy has always been to stick it out until someone
comes up with the right solution to a problem rather than picking some
easy way out.


BTW, unsafePerformIO seems quite pragmatic and easy to me, so let's
not get too snobby about this. (Sorry, I couldn't resist.)

Regards
--
Adrian Hey

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: [Haskell] Top Level -

2008-08-28 Thread Brandon S. Allbery KF8NH


On 2008 Aug 28, at 20:45, Adrian Hey wrote:


Lennart Augustsson wrote:

If Haskell had always taken the pragmatic path of adding what seems
easiest and most in line with imperative practice it would not be the
language it is today.  It would be Perl, ML, or Java.
The Haskell philosophy has always been to stick it out until someone
comes up with the right solution to a problem rather than picking  
some

easy way out.


BTW, unsafePerformIO seems quite pragmatic and easy to me, so let's
not get too snobby about this. (Sorry, I couldn't resist.)



It's anything but easy; there are specific rules you need to follow,  
including use of certain compiler pragmas, to insure it works properly.


--
brandon s. allbery [solaris,freebsd,perl,pugs,haskell] [EMAIL PROTECTED]
system administrator [openafs,heimdal,too many hats] [EMAIL PROTECTED]
electrical and computer engineering, carnegie mellon universityKF8NH


___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: [Haskell] Top Level -

2008-08-28 Thread Dan Doel
On Thursday 28 August 2008 2:28:35 pm David Roundy wrote:
 On Thu, Aug 28, 2008 at 01:17:29PM -0400, Dan Doel wrote:
  On Thursday 28 August 2008 12:26:27 pm Adrian Hey wrote:
   As I've pointed out several times already you can find simple examples
   in the standard haskell libs. So far nobody has accepted my challenge
   to re-implement any of these competantly (I.E. avoiding the use of
   global variables).
  
   Why don't you try it with Data.Unique and find out :-)
 
  Here's a first pass:
 
  -- snip --
 
  {-# LANGUAGE Rank2Types, GeneralizedNewtypeDeriving #-}
 
  module Unique where

 If you want this to actually provide any guarantees, of course, you'll
 have to provide an export list.

Yes, quite right. I didn't spend a lot of time on it. I believe U and unU 
would need to be hidden to prevent people from doing bad things.

Another problem I thought of after the fact is that if you need to extend the 
IO monad in any other similar way, you're out of luck. However, I think you 
can modify things to something like:

newtype UT r m a = UT { unUT :: ReaderT (MVar Integer) m a } ...

runUT :: MonadIO m = (forall r. UT r m a) - m a
runUT m = liftIO (newMVar 0) = runReaderT (unUT m)

...

Or if you want to get really fancy, maybe you could invent an entire new 
sectioned, composable IO monad like Datatypes a la Carte. But that's a fair 
amount more work.

Cheers.
-- Dan
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: [Haskell] Top Level -

2008-08-27 Thread Adrian Hey

Lennart Augustsson wrote:

BTW, I'm not contradicting that the use of global variables can be
necessary when interfacing with legacy code, I just don't think it's
the right design when doing something new.


AFAICS the use of top level mutable state in the base libs has nothing
at all to do with interfacing with legacy code, it's a semantic
necessity and there's no legacy code involved.

If you want to dispute that then please show some real Haskell code that
does as good or better job without it (or point me too the relevant
legacy code that makes it necessary).

Regards
--
Adrian Hey



___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: [Haskell] Top Level -

2008-08-27 Thread Adrian Hey

Lennart Augustsson wrote:

I told you where to look at code.  It's C code, mind you, but written
in a decent way.
No well written device driver ever accesses memory or IO ports
directly, doing so would seriously hamper portability.


Well something must be accessing both. Dunno what you mean by directly
I take it you must mean that the driver does not make use of global
variables or baked in port addresses in it's source code.


Instead you use an abstraction layer to access to hardware, and the
driver gets passed a bus (whatever that might be) access token (akin
to a capability).

I know you're not going to be convinced, so I won't even try. :)


I have actually spent the last 20 years or so writing both non-hosted
and hosted device drivers for a few OS's. I'm perfectly convinced about
the truth of what you say, but not at all convinced about the relevance.

It's a red herring IMO as you've introduced a very complex and
mysterious black box that itself cannot be implemented without making
use of global variables. You can find them easily enough in the Linux
kernel source. I'm sure they'll be there in NetBSD too (never looked
though).

Regards
--
Adrian Hey


___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: [Haskell] Top Level -

2008-08-27 Thread Lennart Augustsson
I've also written quite a few hosted and non-hosted device drivers (in C).
None of them have any global variables.

On Wed, Aug 27, 2008 at 9:07 AM, Adrian Hey [EMAIL PROTECTED] wrote:
 Lennart Augustsson wrote:

 I told you where to look at code.  It's C code, mind you, but written
 in a decent way.
 No well written device driver ever accesses memory or IO ports
 directly, doing so would seriously hamper portability.

 Well something must be accessing both. Dunno what you mean by directly
 I take it you must mean that the driver does not make use of global
 variables or baked in port addresses in it's source code.

 Instead you use an abstraction layer to access to hardware, and the
 driver gets passed a bus (whatever that might be) access token (akin
 to a capability).

 I know you're not going to be convinced, so I won't even try. :)

 I have actually spent the last 20 years or so writing both non-hosted
 and hosted device drivers for a few OS's. I'm perfectly convinced about
 the truth of what you say, but not at all convinced about the relevance.

 It's a red herring IMO as you've introduced a very complex and
 mysterious black box that itself cannot be implemented without making
 use of global variables. You can find them easily enough in the Linux
 kernel source. I'm sure they'll be there in NetBSD too (never looked
 though).

 Regards
 --
 Adrian Hey


 ___
 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


Re: [Haskell-cafe] Re: [Haskell] Top Level -

2008-08-27 Thread Adrian Hey

Lennart Augustsson wrote:

I've also written quite a few hosted and non-hosted device drivers (in C).
None of them have any global variables.


The point is to be able to properly model, understand and if necessary
implement *entire systems* without using global variables (allegedly).

You can always define sub-system boundaries in such a way that you can
claim that this/that or the other sub-system, device driver or whatever
does not use global variables if you put the global variables
somewhere else and pass a reference to the sub-system concerned.
We could play that game with Data.Unique, for example.

Regards
--
Adrian Hey

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: [Haskell] Top Level -

2008-08-27 Thread John Meacham
On Wed, Aug 27, 2008 at 02:23:04AM +0100, Lennart Augustsson wrote:
 BTW, I'm not contradicting that the use of global variables can be
 necessary when interfacing with legacy code, I just don't think it's
 the right design when doing something new.

As with all design decisions, it is sometimes the right thing and
sometimes the wrong one. And sometimes the most expedient. (which,
occasionally, is a perfectly valid driving force behind a certain bit of
coding). However, I am fully convinced it is necessary. You don't even
have to look further than Haskell 98 to find a use in the Random module,
and Data.Unique _depends_ on the state being global for correctness.

now, _interfaces_ that depend on global state are a completely different
matter. To quote what I wrote in the jhc manual:

Note, top level global variables can be indicative of design issues. In
general, they should only be used when necessary to interface with an
external library, opaque uses inside a library where the shared state
can not be externally observed, or inside your Main program as design
dictates.

However, note the weasel words. Those are in there on purpose, every
design calls for different solutions. To blanketly say certain
constructs are just wrong to the point of disallowing them in the
language, especially when they are common practice at the moment, just
doesn't seem right.

John

-- 
John Meacham - ⑆repetae.net⑆john⑈
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: [Haskell] Top Level -

2008-08-27 Thread Adrian Hey

John Meacham wrote:

As with all design decisions, it is sometimes the right thing and
sometimes the wrong one. And sometimes the most expedient. (which,
occasionally, is a perfectly valid driving force behind a certain bit of
coding). However, I am fully convinced it is necessary. You don't even
have to look further than Haskell 98 to find a use in the Random module,
and Data.Unique _depends_ on the state being global for correctness.


..and of course there's stdin, stdout. That takes some explaining. Even
with the proposed ACIO and top level - bindings I still couldn't
implement a lib that exported a top level nonStdout handle. It'd have to
be a getNonStdout IO action.

Regarding the necessity of global variables, despite what I've been
saying it is of course possible to implement entire systems
(programs/processes or whatever main corresponds to) without them if
you don't mind explicitly creating all those micro states immediately
on entry to main and passing the references around.

But this is a highly unmodular, inconvenient, unsafe (because you must
expose and allow potentially uncontrained use of newWhateverMicroState
constuctors) and a general maintainance nightmare. Definitely not the
way to go IMO.

So it would be more accurate to say that IMO it's impossible to
implement many sane and inherently safe IO lib APIs without using
global variables. But people who prefer insane and inherently unsafe
APIs could live without them quite happily I guess :-)

Regards
--
Adrian Hey


___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: [Haskell] Top Level -

2008-08-27 Thread Adrian Hey

Judah Jacobson wrote:

I've been wondering: is there any benefit to having top-level ACIO'd
- instead of just using runOnce (or perhaps oneshot) as the
primitive for everything?  For example:

oneshot uniqueRef :: IO (MVar Integer)
uniqueRef = newMVar 0


I've been wondering about something like this too (in some way just have
a oneShot or runOnce and the *only* thing in ACIO as a magic primitive).

runOnce :: IO a - ACIO (IO a)

It would certainly simplify the ACIO monad :-), but I'm not sure it's
really as flexible. Provided newMVar can be ACIO then this can be
implemented directly (doesn't need to be a primitive). But we can't
go the other way round (use runOnce to create genuine top level MVars
or channels say).

Does that matter? Probably not for monadic IO code. It's not a huge
inconvenience to write..

 do ...
thing - getThing
foo thing

vs..
 do ...
foo thing -- thing is at top level

But for top level non monadic code/expressions/data structures I can
see a certain convenience in having thing as top level identifier
if possible, which it often won't be anyway I guess for other
reasons (like it's creation and initialisation requires real IO).

So I don't have any particularly strong opinion either way. In
practice if thing (or getThing) is to be exported then it
would probably be prudent to assume creation and initialisation
might require real IO at some point in the future even if they
don't right now, so you'd export getThing (= return thing) anyway,
rather then have an exported thing dissappear from the API at some
point.

My 2p..

Regards
--
Adrian Hey











___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: [Haskell] Top Level -

2008-08-27 Thread John Meacham
I think a strong advantage of the straight up ACIO formulation (rather
than a one-shot IO based thing) is that it can be fully, correctly, and
safely be defined without referencing the IO monad or its interaction
with the IO monad at all. In practice, ACIO will be generally be used to
interact with IO code. But being able to formalize it completely
independently of the IO monad and all the IO monad entails is an
enticing posibility.

John

-- 
John Meacham - ⑆repetae.net⑆john⑈
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: [Haskell] Top Level -

2008-08-27 Thread Adrian Hey

Lennart Augustssom wrote:
Since at some point you have to interface with the hardware you are 
forced to obey whatever convention is used for interrupts etc. At that 
point you may very well have to use global variables. But you can 
quickly abstract away from that in stay in the safe land without globals.


BTW, did you notice that the non-hosted driver API example I put on the
wiki page doesn't use globals either :-) The two device handles are
at the top level (are globals as you would say), but the driver
code takes these as an argument so doesn't care if they're top
level or not.

If I don't have the device handles at the top level or some means to get
them from the top level then I have no alternative but to export
createDeviceHandle either directly to the user level API (really bad!)
or to some other bit of higher level system code that can be trusted not
to create 2 or more handles for the same device (and no handles for
non-existant devices). Let's assume it's that latter.

In the simple case where it is known at compile time that there are
exactly 2 devices in the system at known base addresses, can you explain
how the higher level bit of the system guarantees that user level
application code will only ever have access to 2 different device
handles in total (one for each device), no matter what?

How does it solve this problem in the more complex complex case where
hardware must be probed somehow to discover how many devices there
are and where they are?

All without using any global variables please. Also, assuming you
succeed, please explain what advantages or extra safety your solution
provides over a solution which does use global variables.

The obvious solution seems to be to have this code present this function
to the user level API..

getAvailableDeviceHandles :: IO [DeviceHandle]

Which shouldn't be hard to implement in either case, except for the fact
IO state getters can't be implemented at all without top level mutable
state or runOnce primitives or something like that (AFAICS).

newAvailableDeviceHandles perhaps? I guess that could come in handy
if the user code decides it doesn't like the old ones for some
reason :-)

Regards
--
Adrian Hey





___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: [Haskell] Top Level -

2008-08-27 Thread Jonathan Cast
On Wed, 2008-08-27 at 11:53 +0100, Adrian Hey wrote:
 John Meacham wrote:
  As with all design decisions, it is sometimes the right thing and
  sometimes the wrong one. And sometimes the most expedient. (which,
  occasionally, is a perfectly valid driving force behind a certain bit of
  coding). However, I am fully convinced it is necessary. You don't even
  have to look further than Haskell 98 to find a use in the Random module,
  and Data.Unique _depends_ on the state being global for correctness.
 
 ..and of course there's stdin, stdout. That takes some explaining.

Not really.  If you don't have buffered IO, then you just say

stdin = 0
stdout = 1
stderr = 2

If you need buffered IO, you just change your IO monad* to look like:

newtype NewIO alpha = NewIO (ReaderT (Map Fd Buffer) OldIO alpha)

Of course, if you do this, you can't go mixing IO with unique values
with RNG with mutable state with everything else under the sun anymore.
You might actually have to declare exactly what effects you need when
you give your function's type, now.  Clearly, a horror we must avoid at
all costs.

jcc

* I wonder why that name was chosen?  The design doesn't seem to have
anything to do with IO, it's more of a `we have this in C so we want it
in Haskell too' monad.

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: [Haskell] Top Level -

2008-08-27 Thread Derek Elkins
On Wed, 2008-08-27 at 02:35 -0700, John Meacham wrote:
[cut]
 
 However, note the weasel words. Those are in there on purpose, every
 design calls for different solutions. To blanketly say certain
 constructs are just wrong to the point of disallowing them in the
 language, especially when they are common practice at the moment, just
 doesn't seem right.

How can a Haskell user say this?  And this is indeed exactly what
capability languages do.  In fact, this is what almost every language
does (for one thing in common practice or another.) 

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: [Haskell] Top Level -

2008-08-27 Thread Daniel Fischer
Am Mittwoch, 27. August 2008 22:57 schrieb Jonathan Cast:
 On Thu, 2008-08-28 at 00:53 +0400, Bulat Ziganshin wrote:
  Hello Jonathan,
 
  Wednesday, August 27, 2008, 8:12:42 PM, you wrote:
   * I wonder why that name was chosen?  The design doesn't seem to have
   anything to do with IO, it's more of a `we have this in C so we want it
   in Haskell too' monad.
 
  s/it/exchange with external world, i.e., essentially, I/O/

 Bald assertion.  I don't buy it.  What do IORefs have to do with
 exchange with the external world?

 jcc


Well, you wrote
snip
 change your IO monad*
snip
 * I wonder why that name was chosen?  The design doesn't seem to have
 anything to do with IO, it's more of a `we have this in C so we want it
 in Haskell too' monad.

I believe, Bulat took it to include getLine, readFile, writeFile et al.
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: [Haskell] Top Level -

2008-08-27 Thread Ganesh Sittampalam

On Wed, 27 Aug 2008, Jonathan Cast wrote:


* I wonder why that name was chosen?  The design doesn't seem to have
anything to do with IO, it's more of a `we have this in C so we want it
in Haskell too' monad.


The 'C' in ACIO says that it commutes with any operation in the IO
monad. Without that property you can't safely implement it in a
program where the top-level has type IO a.

http://www.haskell.org/pipermail/haskell-cafe/2004-November/007664.html

Ganesh
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: [Haskell] Top Level -

2008-08-27 Thread Jonathan Cast
On Wed, 2008-08-27 at 23:20 +0200, Daniel Fischer wrote:
 Am Mittwoch, 27. August 2008 22:57 schrieb Jonathan Cast:
  On Thu, 2008-08-28 at 00:53 +0400, Bulat Ziganshin wrote:
   Hello Jonathan,
  
   Wednesday, August 27, 2008, 8:12:42 PM, you wrote:
* I wonder why that name was chosen?  The design doesn't seem to have
anything to do with IO, it's more of a `we have this in C so we want it
in Haskell too' monad.
  
   s/it/exchange with external world, i.e., essentially, I/O/
 
  Bald assertion.  I don't buy it.  What do IORefs have to do with
  exchange with the external world?
 
  jcc
 
 
 Well, you wrote
 snip
  change your IO monad*
 snip
  * I wonder why that name was chosen?  The design doesn't seem to have
  anything to do with IO, it's more of a `we have this in C so we want it
  in Haskell too' monad.
 
 I believe, Bulat took it to include getLine, readFile, writeFile et al.

These things existed in Haskell 1.0, before IORefs ever did.

jcc


___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


  1   2   >