Re: [Haskell-cafe] Language support for imperative code. Was: Re: monad subexpressions
Brian Hulley wrote: Haskell is designed so that any attempt at abstracting mutable local state will infect the entire program (modulo use of a highly dangerous function whose semantics is entirely unclear, depending on the vagaries of evaluation strategy of the particular compiler) (Your email message is long and very interesting, and it does an a considerable injustice to take one sentence out of context, but...) This echoes a misconception that I see here on haskell-cafe quite often. Mutable local state *really* doesn't need to infect the whole program, and haskell is certainly not designed so it must. We have all kinds of techniques for ensuring that the pure parts of your code can remain pure, and only the impure parts get 'infected' with an IO signature. Additionally, if it's just refs, you can use ST, which is totally pure. If it's literally just state, you can use the techniques of the State monad and the Reader monad: but you don't necessarily have to use them explicitly with those names. Sometimes it is actually simpler just to use the types s - (a,s) and s - a directly; only in certain circumstances is the extra plumbing useful. Often different parts of your program have different needs; some parts actually need the ability to make fresh names (and so need STRefs) other parts merely read the state (and can use Reader techniques) and other parts alter it (and can use State techniques). You need some plumbing to connect the different parts together, but fortunately haskell has powerful abstraction and it's quite easy to slap together the higher-order functions (combinators!) to do this. Jules ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
[Haskell-cafe] Language support for imperative code. Was: Re: monad subexpressions
apfelmus wrote: However, most genuinely imperative things are often just a building block for a higher level functional model. The ByteString library is a good example: the interface is purely functional, the internals are explicit memory control. It's a bad idea to let the internal memory control leak out and pollute an otherwise purely functional program with IO-types. Hi Apfelmus, This is a really interesting discussion that touches on issues I'm currently working with (I'm designing a strict version of Haskell to explore various ideas about modules, namespace management, and how to get really efficient machine code but without losing the convenience of accurate garbage collection etc, but I'm having difficulties deciding between the monadic path and the impure path), so I've forked this new thread. Regarding the quote above, if the API must hide explicit memory control from the user the only way I can see of doing this would be to use (unsafePerformIO), which really is unsafe since Haskell relies on the fact that mutable operations can't escape from the IO monad in order to get away with not having to impose a value restriction as in ML. If you don't use (unsafePerformIO), then the slightest need for mutable data structures pollutes the entire interface. For example in the excellent paper you quoted N. Ramsey and J. Dias. An Applicative Control-Flow Graph Based on Huet's Zipper http://www.eecs.harvard.edu/~nr/pubs/zipcfg-abstract.html http://www.eecs.harvard.edu/%7Enr/pubs/zipcfg-abstract.html the authors are pleased to have found an Applicative solution, and indeed their solution has many useful and instructive aspects. However on page 111, hidden away in the definition of their API function to create a label, is a call to (ref 0) ;-) The equivalent implementation in Haskell would completely destroy all hope of using this in a pure context and force all use of the API into the IO monad. Haskell and ML seem to stand at opposite poles. Haskell is designed so that any attempt at abstracting mutable local state will infect the entire program (modulo use of a highly dangerous function whose semantics is entirely unclear, depending on the vagaries of evaluation strategy of the particular compiler) whereas people have been struggling in the ML community for at least 15 years to try and find a way to hide the fact that mutable storage is being used (cf attempts to find a proper solution to the unsoundness introduced by polymorphism and ref without having to use imperative/weak type variables etc). Meanwhile, C++, C#, and Java programmers get a type system (thinking only about static methods using generics/templates) that seems to me no less powerful than that of the prenex polymorphism of ML, yet without any of the unsoundness problems, and therefore without the need of a value restriction (afaiu this is because their template/generic definitions stand in for an infinite family of monomorphic bindings instead of ML which tries unsuccessfully to make one piece of memory represent each element of an infinite family of values simultaneously). Not only this, but there seems to me to be many problems for which it is natural to think in terms of objects with identity and mutable state. I can readily discard the concepts of deep inheritance hierarchies and open recursion but this still leaves the problem of identity and localised mutability. For example consider a simple GUI with 2 edit widgets, a splitter, and a single buffer that contains the text being edited. The idea is that you should be able to use either edit widget to interact with the same buffer eg to edit at different locations in the buffer. A simple imperative solution might be something like: main = do buffer - createBuffer edit1 - createEdit buffer edit2 - createEdit buffer splitter - createSplitter (wrapWidget edit1) (wrapWidget edit2) runMessageLoopWith splitter Here it's really clear what's happening, and different objects in the program correspond exactly to how I think about what I'm trying to do ie I want to create individual objects with identity and then plug them together. I don't want to have to bother about passing state around, or having to define a new data type every time I want a different configuration of widgets. Thus the ability to abstract mutable state gives to my mind by far the best solution. In contrast, all the pure functional GUIs that I've seen are just wrappers around someone else's imperative code, and moreover, they exchange the simplicity of the object oriented imperative API for a veritable mindstorm of unbelievably heavy, clunky, slow, inefficient, inextensible, hard to understand encodings that seem to me to have the effect of turning a high level language into some kind of circuit board (I'm thinking of arrows etc). Indeed everyone seems to be using either WxWidgets or
Re: [Haskell-cafe] Language support for imperative code. Was: Re: monad subexpressions
Brian Hulley wrote: hidden away in the definition of their API function to create a label, is a call to (ref 0) ;-) The equivalent implementation in Haskell would completely destroy all hope of using this in a pure context and force all use of the API into the IO monad. Really? I would have thought this is a job for the ST monad, in which case the API can be wrapped up in a runST or similar; no need for leaking IO monads. Or am I missing something? Regards, Martin My music: http://www.youtube.com/user/thetonegrove (please visit!) ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Language support for imperative code. Was: Re: monad subexpressions
On 8/8/07, Brian Hulley [EMAIL PROTECTED] wrote: In contrast, all the pure functional GUIs that I've seen are just wrappers around someone else's imperative code, and moreover, they exchange the simplicity of the object oriented imperative API for a veritable mindstorm of unbelievably heavy, clunky, slow, inefficient, inextensible, hard to understand encodings that seem to me to have the effect of turning a high level language into some kind of circuit board (I'm thinking of arrows etc). In defense of Haskell (wow!), note that imperative languages are not without problems in GUIs. In a multithreaded environment, typically only one thread is allowed to manage the GUI, and then you typically need to set up some sort of message-passing system to communicate between this thread and the others AFAIK? This is a total PITA, so if someone has a solution for this that would rock :-) Question: to what extent do the Haskell wrappers around gtk and wxWidgets suffer from this problem? I mean, I havent tried them, so it's a genuine question. (Note: off the top of my head, in an imperative language, I guess one could use some sort of generator to take an interface and generate the message classes, and marshalling classes automatically) (Disclaimer: I havent really searched very hard for ways to handle threading in GUIs in imperative languages, since mostly I either use web pages as the visual interface, which avoids around the problem, or use a single thread, which also avoids the problem) ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Language support for imperative code. Was: Re: monad subexpressions
On 8/8/07, Brian Hulley [EMAIL PROTECTED] wrote: Regarding the quote above, if the API must hide explicit memory control from the user the only way I can see of doing this would be to use (unsafePerformIO), which really is unsafe since Haskell relies on the fact that mutable operations can't escape from the IO monad in order to get away with not having to impose a value restriction as in ML. My theory is weak. Can somebody point me the way to educate myself about the value restriction in ML? Thanks! -Corey -- -Corey O'Connor ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Language support for imperative code. Was: Re: monad subexpressions
Martin Percossi wrote: Brian Hulley wrote: hidden away in the definition of their API function to create a label, is a call to (ref 0) ;-) The equivalent implementation in Haskell would completely destroy all hope of using this in a pure context and force all use of the API into the IO monad. Really? I would have thought this is a job for the ST monad, in which case the API can be wrapped up in a runST or similar; no need for leaking IO monads. Or am I missing something? Well I agree you're right on this particular use of a Ref, since their program is only dealing with a mapping from input to output so once they're finished using the data structure there is no longer any need for the ref and so the result can be returned to the rest of the program. However there are 2 problems with this approach in general afaics: 1) All code that uses this data structure ie that participates in the implementation of the transformations by using the API functions will have to be in a monad (ST or IO, it really doesn't matter in terms of all the perceived burdensomeness of do notation relative to normal applicative code). 2) The example doesn't transfer to an interactive situation, where we would need to keep the data structure around and use it forever - because we would be forever trapped inside the ST monad otherwise we'd lose that particular STRef which we were hoping to use to efficiently update the output in the face of a delta in the input. Corey - I found this page helpful to get an understanding of the value restriction in ML: http://www.smlnj.org/doc/Conversion/types.html The restriction was proposed by Andrew Wright in 1995: Simple Imperative Polymorphism by Wright http://citeseer.ist.psu.edu/wright95simple.html Some other related papers are: The Type and effect discipline by Talpin and Jouvelot 1992 Standard ML-NJ weak polymorphism and imperative constructs by Hoang, Mitchell, and Viswanathan Weak polymorphism can be sound by Greiner 1993 and more recently (2003) Relaxing the value restriction by Garrigue http://citeseer.ist.psu.edu/garrigue03relaxing.html (Note that even now there is still no real solution to it.) Best regards, Brian. ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Language support for imperative code. Was: Re: monad subexpressions
Hugh Perkins wrote: On 8/8/07, *Brian Hulley* [EMAIL PROTECTED] mailto:[EMAIL PROTECTED] wrote: In contrast, all the pure functional GUIs that I've seen... In defense of Haskell (wow!), note that imperative languages are not without problems in GUIs. In a multithreaded environment, If you're using multiple threads you'd need to be in the IO monad to create/manipulate the MVars or TVars or whatever. (In contrast to eg AliceML where you could easily use a synchronising logic variable without having to leave all the familiar applicative coding comforts behind to brave the fiercesome lonely toil of Monadia ;-)) typically only one thread is allowed to manage the GUI, and then you typically need to set up some sort of message-passing system to communicate between this thread and the others AFAIK? This is a total PITA, so if someone has a solution for this that would rock :-) Question: to what extent do the Haskell wrappers around gtk and wxWidgets suffer from this problem? I mean, I havent tried them, so it's a genuine question. I don't know though I seem to recall some info on this on the website of Gtk2Hs. (Note: off the top of my head, in an imperative language, I guess one could use some sort of generator to take an interface and generate the message classes, and marshalling classes automatically) (Disclaimer: I havent really searched very hard for ways to handle threading in GUIs in imperative languages, since mostly I either use web pages as the visual interface, which avoids around the problem, or use a single thread, which also avoids the problem) So far I've always managed to get away with just using a single threaded GUI. I think you run into problems with XLib and OpenGL (on GNU/Linux at least) if you try to call into those APIs from multiple threads and also it seems better to separate concerns by having all rendering code, including cacheing of geometry etc, in the same thread since it's easy enough to spawn new threads to do calculations and set a flag in the relevant widget when the result is complete... Best regards, Brian. ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Language support for imperative code. Was: Re: monad subexpressions
brianh: Hugh Perkins wrote: On 8/8/07, *Brian Hulley* [EMAIL PROTECTED] mailto:[EMAIL PROTECTED] wrote: In contrast, all the pure functional GUIs that I've seen... In defense of Haskell (wow!), note that imperative languages are not without problems in GUIs. In a multithreaded environment, If you're using multiple threads you'd need to be in the IO monad to create/manipulate the MVars or TVars or whatever. (In contrast to eg AliceML where you could easily use a synchronising logic variable without having to leave all the familiar applicative coding comforts behind to brave the fiercesome lonely toil of Monadia ;-)) Or use purely functional channels (Chan). -- Don ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe