tag:blogger.com,1999:blog-6913397465984649777.post4450302941445054336..comments2023-07-29T04:40:45.155-07:00Comments on araujo's blog: Haskell for GUI Programingaraujohttp://www.blogger.com/profile/03804288532569108100noreply@blogger.comBlogger16125tag:blogger.com,1999:blog-6913397465984649777.post-42118461805351769612008-04-28T20:25:00.000-07:002008-04-28T20:25:00.000-07:00it is interesting, that you stay away from IORefs ...<I>it is interesting, that you stay away from IORefs (I can't do that). Could you tell me how do you achieve this: two buttons, one when clicked, prints number of times it has been clicked to stdout, seconed button resets to 0 on click.</I><BR/><BR/>As explained in some previous comments , there _exist_ IORefs , but they are internal to the gtk2hs library ; so I just use them 'implicitly' if you want to call it so.<BR/><BR/>It's just a matter of how you design your own application , from my second post on this thread:<BR/><I><BR/>1 - Small functions with well defined behaviours.<BR/>2 - A coherent data flow passing through the arguments of each functions.<BR/></I><BR/>These are two factors that really helps to reduce or even remove the need for explicit IORefs in your application code.<BR/><BR/>Following a more pragmatic explanation of your button example; one way that comes from the top of my head right now to avoid explicit IORefs would be to encapsulate the count into one of the object components of gtk2hs ; for example you could save the value inside a widget container.<BR/><BR/>This will evidently be using mutable state , but underneath your code , and it won't bring out any unnecessary IORef to the application explicitly. This approach have been substantially productive for me , in any case, IORefs are (in my opinion) more a way to address internal behaviour inside an application (library bindings in this case) , than a common user level construct, and it's the way I am using them so far.<BR/><BR/>Thanks and Regards,araujohttps://www.blogger.com/profile/03804288532569108100noreply@blogger.comtag:blogger.com,1999:blog-6913397465984649777.post-77934174912386057672008-04-28T20:09:00.000-07:002008-04-28T20:09:00.000-07:00This problem is not especially linked to GUI desig...<I>This problem is not especially linked to GUI design, but more generally to any haskell program manipulating complicated and deep datatypes.</I><BR/><BR/>Correct.<BR/><BR/>Functional references are definitely a good approach for this issue.<BR/><BR/>Thanks for your post,araujohttps://www.blogger.com/profile/03804288532569108100noreply@blogger.comtag:blogger.com,1999:blog-6913397465984649777.post-33382117945525591182008-04-25T10:33:00.000-07:002008-04-25T10:33:00.000-07:00it is interesting, that you stay away from IORefs ...it is interesting, that you stay away from IORefs (I can't do that). Could you tell me how do you achieve this: two buttons, one when clicked, prints number of times it has been clicked to stdout, seconed button resets to 0 on click.Paczesiowahttps://www.blogger.com/profile/14436047943969802962noreply@blogger.comtag:blogger.com,1999:blog-6913397465984649777.post-52242095208000617282008-04-25T04:03:00.000-07:002008-04-25T04:03:00.000-07:00damn link.Just type "overloading functional refere...damn link.<BR/><BR/>Just type "overloading functional references" in google and feel lucky.tgirodhttps://www.blogger.com/profile/01286596579304245988noreply@blogger.comtag:blogger.com,1999:blog-6913397465984649777.post-64504487197888278412008-04-25T03:59:00.000-07:002008-04-25T03:59:00.000-07:00Say your program maintains a pretty deep data stru...<I>Say your program maintains a pretty deep data structure that consists of nested records. What do you do if you need to update a field somewhere deep down in this structure in response to an event? You can't just poke at the field like in Java/any other imperative language. You need to reconstruct the entire thing.<BR/><BR/>*Very* inconvenient.</I><BR/><BR/>(I didn't read all the comments so I hope this is not a dupe but anyway ...)<BR/><BR/>This problem is not especially linked to GUI design, but more generally to any haskell program manipulating complicated and deep datatypes.<BR/><BR/>I'm currently developing a program of that sort, so I stumbled on this problem : how can I modify one field lost deep into my complicated datatype ? haskell offers syntactic sugar for the simple case :<BR/><BR/>> myData {myField = newValue}<BR/><BR/>but it doesn't work when you want to change a field wiithin "myField".<BR/><BR/>Well, there is an elegant solution : "functional references". Basically, it allows you to build getters and setters functions for all your datatypes, with the huge advantage of being composable. That way, you can do things that looks like :<BR/><BR/>> let myNewData = set (firstField . innerField) myData newValue<BR/><BR/>There is a very good example here :<BR/><BR/>http://twan.home.fmf.nl/blog/haskell/overloading-functional-references.detailstgirodhttps://www.blogger.com/profile/01286596579304245988noreply@blogger.comtag:blogger.com,1999:blog-6913397465984649777.post-56635021679343386102007-04-27T19:44:00.000-07:002007-04-27T19:44:00.000-07:00You are slightly confused there.f :: a -> IO a is ...You are slightly confused there.<BR/><BR/>f :: a -> IO a is a perfectly pure function, it just happen to contain code with side-effect. That's why monads are usually explained as containers, since they just encapsulate this code, but preserves the purity of the function.<BR/><BR/>gtk2hs takes care of the mutable state, i myself didn't have to explicitly create and manipulate such a references (like using IORef types) on my code; as opposed to the common practice of including such a behaviour and design on GUI programing. I probably had to be clearer about it though.<BR/><BR/>Regards,araujohttps://www.blogger.com/profile/03804288532569108100noreply@blogger.comtag:blogger.com,1999:blog-6913397465984649777.post-70506911603018151992007-04-27T18:43:00.000-07:002007-04-27T18:43:00.000-07:00Ok, I think you might have misunderstood some thin...Ok, I think you might have misunderstood some things about Haskell. <BR/><BR/>A function f :: a -> I0 a is not a pure (referentially transparent) function, hence the IO type. Okay, you can argue that the whole program is a function that transforms the world, but that's not the usual view of programs. <BR/><BR/>I took a look at hImerge just to see if there's something I'm missing, but it turns out that you are using mutable state all over the place AFAICS, by storing and manipulating it in the widgets directly. This is not different to using IORefs to capture mutable state. This approach doesn't solve the problem I mention.David Waernhttps://www.blogger.com/profile/04685936983595019433noreply@blogger.comtag:blogger.com,1999:blog-6913397465984649777.post-78308446959342433092007-04-27T17:46:00.000-07:002007-04-27T17:46:00.000-07:00If I didn't have an IORef around each package, I'd...<I>If I didn't have an IORef around each package, I'd have to write more code here. ...</I><BR/><BR/>You probably will, but it might still be less code than in an imperative language.<BR/><BR/><I>I'd have to write a function that has the type Model -> Model, that just changes the particular field inside the particular package inside the model. Then update the model using the "global" IORef.</I><BR/><BR/>That was one of the point of my comment , that is _actually_ possible and convenient to avoid mutable state in GUI programming using Haskell, you keep thinking in terms of _updating_ , because that's the 'imperative' way of doing it.<BR/><BR/>I precisely believe that designing your program with a coherent data flow passing through functions arguments avoid the mutable state approach (among other design patterns). If that's the way you want to do it, it's up to you, but i have personally found it easier to reason about it instead of global or local mutable structures. <BR/><BR/><I>Do you see the problem?</I><BR/><BR/>Seriously, i don't see it. Either the IORef and the non-usage of mutable state is a valid pure approach in Haskell.<BR/><BR/>And i really find the example of the Show class irrelevant for the subject. If a data type can belong or not to a class doesn't necessarily make a function more pure than other.<BR/><BR/><I>Note that, in my opinion, you NEED the direct-updating feature if you are arguing that GUI programming in the IO monad using gtk2hs is as easy as doing the same style of GUI programming in an imperative language.</I><BR/><BR/>It's precisely my point, that Haskell programming without mutable references can be as easy or even easier to develop than the imperatives approaches.<BR/><BR/>But you need to design your _whole_ program functionally. And that might require a mind-change too.<BR/><BR/>All your points, though valid at some degree, are still coming from an imperative perspective, for example, you keep insisting in monadic code being impure (or at least, what i have understood so far) , or that you _need_ a mutable data structure because you need to change a specific model.<BR/><BR/>Let's see if i try to explain myself better.<BR/><BR/>You have to treat your _whole_ program as a function, instead of some parts of it; if you start looking at it from that perspective, you will realize, that mutable states can be omitted, or might be unnecessary to accomplish a similar functionality.<BR/><BR/>My main point is that, encapsulating, or packaging possible mutable variables around your code, though it might give you a smaller code, i have found that a design, where you can access _all_ the possible model state through the normal variable declarations and along with well defined data types (and i mean, data types designed with the whole program as a function in mind) can offer more advantages instead of the common approach of a global structure , or even a local one to update in-place; some them: easier to track variable's life and contents, less functions inside the IO monad (Show available), it can avoid the creation of ADT with mutable state, and many more.<BR/><BR/>And with all this, the code will more likely be smaller than in an imperative language. I know it's difficult to believe it, i myself couldn't believe it either, until i started trying it by myself, and i invite you to do it too.<BR/><BR/>Regards,araujohttps://www.blogger.com/profile/03804288532569108100noreply@blogger.comtag:blogger.com,1999:blog-6913397465984649777.post-23391670193629790202007-04-27T16:09:00.000-07:002007-04-27T16:09:00.000-07:00Okay, I'm sorry, perhaps I should try to write les...Okay, I'm sorry, perhaps I should try to write less cryptic posts.<BR/><BR/>The pure function I'm talking about is an entirely different function. It doesn't have anything to do with the event handler. <BR/><BR/>I want to be able to write both the event handler, that does direct updating of fields, AND the pure function that processes the data structure. Imagine a program that both responds to events AND does some kind of core program functionality that is entirely purely functional. The problem is that you would need two different data structures for this, an imperative one that contains references, and a more "functional" one without references.<BR/><BR/>Here's an example of the problem:<BR/><BR/>data Gui = Gui {<BR/> widgetA :: Widget,<BR/> widgetB :: Widget,<BR/> ..<BR/> ..<BR/> model :: IORef IdeModel<BR/>}<BR/><BR/>data IdeModel = IdeModel {<BR/> packages :: [IORef Package],<BR/> documents :: [Document],<BR/> .. etc<BR/>}<BR/><BR/>data Package = Package {<BR/> rootDir :: FilePath,<BR/> descr :: PackageDescription,<BR/> lbi :: Maybe LocalBuildInfo<BR/>}<BR/><BR/>Now, say you have a preference panel where the user can configure local settings for a selected package, like what arguments to pass to "configure". When the user press "Apply" for this panel, the lbi field needs to be set to Nothing, to indicate that the configure step needs to be re-run (say a background thread handles building the package).<BR/><BR/>I have one IORef to the whole model, because I want to be able to update the model. But I also have an IORef for each package, because it is convenient to be able to directly poke at a package. Like in the apply button event:<BR/><BR/>onApply gui packageName settings = do<BR/> -- local settings changed,<BR/> -- need to set lbi field of package<BR/> -- to Nothing.<BR/> pkgRef <- lookupPackage gui packageName<BR/> modifyIORef pkgRef (\p -> p { lbi = Nothing })<BR/> -- do other things with the settings<BR/> ...<BR/><BR/>If I didn't have an IORef around each package, I'd have to write more code here. I'd have to write a function that has the type Model -> Model, that just changes the particular field inside the particular package inside the model. Then update the model using the "global" IORef. That's pretty inconvenient, and thanks to the per-package IORef I don't have to do that. And this, wrapping a field inside an IORef, is something you'd do for every specific field/data structure that you want to directly update, to avoid the incovenience of reconstructing the whole model.<BR/><BR/>So far so good, but what if I want to apply this function to the model:<BR/><BR/>show :: Show a => a -> String<BR/><BR/>I can't because I can't instantiate the IdeModel structure in the Show class. Atleast not if I want to show the packages, since they are wrapped in IORef's.<BR/><BR/>Do you see the problem? You choose between the direct-updating feature,<BR/>and being able to apply normal pure Haskell functions in various ways to the data you are working with.<BR/><BR/>You don't really choose between that when programming in an imperative language because the distinction between references and values is not that strong. <BR/><BR/>Note that, in my opinion, you NEED the direct-updating feature if you are arguing that GUI programming in the IO monad using gtk2hs is as easy as doing the same style of GUI programming in an imperative language.<BR/><BR/>To point this out was the reason for my original comments.<BR/><BR/>Btw, all of this only applies if you really do any fundamental processing of your data structure that best can be done in a pure way. Otherwise it's of course fine to have references everywhere.<BR/><BR/>Hopefully I've ranted enough and made myself a bit more clear now :)<BR/><BR/>I should also say that I like Haskell and am using gtk2hs currently.David Waernhttps://www.blogger.com/profile/04685936983595019433noreply@blogger.comtag:blogger.com,1999:blog-6913397465984649777.post-81473486675820786882007-04-27T14:14:00.000-07:002007-04-27T14:14:00.000-07:00In an imperative language...Your code example is _...<I>In an imperative language...</I><BR/><BR/>Your code example is _very_ imperative , so it makes more sense in an imperative design, and probably much more from an imperative language. That's why i ended up my last comment considering that it is important to think functional while using a functional language, many things are very evident when you do so.<BR/><BR/>I see you also imply many mis-conceptions in your posts, for example, that IO functions aren't pure or .. not _so_ pure like other functions, if that can make sense at all, so i really don't get what you mean.<BR/><BR/>A function of type , f :: Model -> IO Model would be as pure as f :: Model -> Model , making the IORef solution pretty valid, nevertheless, i still think there are better ways , or if you want to call it like this, more functional ways of solving this:<BR/><BR/><I><BR/>onSomeEvent(model) {<BR/>forAll(x <- model.stuff, pred(x))<BR/>{<BR/>x.someField.someOtherField := y<BR/>}<BR/>}<BR/></I><BR/><BR/>If i got your pseudo-code right:<BR/><BR/>data Model = ... // describe it whatever way you want<BR/><BR/>onSomeEvent :: [Model] -> IO [Model]<BR/>onSomeEvent = return . map f where { f :: Model -> Model; f model = ... }<BR/><BR/>Notice how your code is omitting many obvious concepts here, for example, mapping and returning a value of the same data type that is received, plus, practically all the representation comes from the ADT, and not a mutable global structure, even, the behaviour of the function is itself determined by the representation you want to give to the ADT, and it does it in a perfectly pure way.<BR/><BR/>This kind of code and design is so common in Haskell (and functional programing), that the language itself even offers a class, called Functor, that helps to do precisely that, to delegate the behaviour of a function to a specific data type.<BR/><BR/><I><BR/>You can't, because if the function is supposed to do something with the value *inside* someOtherField, it has to have the type Model -> IO Model.</I><BR/><BR/>That's an 'imperative' perception. There is no need to do anything *inside*. Not in this case.<BR/><BR/><I><BR/>But isn't the point of Haskell to do pure processing on your data?</I><BR/><BR/>Always, that's what you do even using IO monads.<BR/><BR/>You keep assuming an IO function is 'impure' or introduces some impurity to the program. I recommend you to check some documentation about it, because it isn't so.<BR/><BR/>Regards,araujohttps://www.blogger.com/profile/03804288532569108100noreply@blogger.comtag:blogger.com,1999:blog-6913397465984649777.post-54962283245084088692007-04-27T12:31:00.000-07:002007-04-27T12:31:00.000-07:00araujo, I think you missed the point, so I'll take...araujo, <BR/><BR/>I think you missed the point, so I'll take an example:<BR/><BR/>In an imperative language you can do:<BR/><BR/>onSomeEvent(model) {<BR/> forAll(x <- model.stuff, pred(x))<BR/> {<BR/> x.someField.someOtherField := y<BR/> }<BR/>}<BR/><BR/>To do that in Haskell someOtherField needs to be an IORef, or you'd have to write lots of code to reconstruct the entire model type. So, the easiest and most practical thing to do is to let it be an IORef, which is what you like to do, right?<BR/><BR/>But then how do you apply the pure function f :: Model -> Model to gui.model?<BR/><BR/>You can't, because if the function is supposed to do something with the value *inside* someOtherField, it has to have the type Model -> IO Model.<BR/><BR/>But isn't the point of Haskell to do pure processing on your data?David Waernhttps://www.blogger.com/profile/04685936983595019433noreply@blogger.comtag:blogger.com,1999:blog-6913397465984649777.post-51624116061334091292007-04-27T11:10:00.000-07:002007-04-27T11:10:00.000-07:00... Yes, you can solve this by putting every field...<I>... Yes, you can solve this by putting every field inside an IORef, but then you can't apply pure processing functions to the structure anymore, so you loose the functional approach. ...</I><BR/><BR/>An IORef is just a mutable reference inside the IO monad, so i don't get what you mean you can't use 'pure processing' functions.<BR/><BR/>As the IO monad, you can perfectly use pure functions inside it, if that's what you mean, and that's pretty much the way the IORef data type works, so, the purity of the approach is preserved.<BR/><BR/><I>... <BR/>This makes IO monad based GUI programming in Haskell very clumsy, for all but the smallest programs. ...</I><BR/><BR/>I don't agree. Haskell is a perfect language for prototyping and rapid development, so the programs tend to be smaller than other approaches (it can even compete with scripting languages); even if you are using monadic code, or a big IO monad, it will more likely keep smaller than an equivalent program in an imperative language. And considering the Brook law of "the time it takes to write a program depends mostly on its length" , i think Haskell can actually be less clumsy than most languages out there.<BR/><BR/><I>... Sadly, functional reactive libraries in Haskell doesn't support more than a few of the basic widgets. Maybe this will change. ...</I><BR/><BR/>Let's hope it changes, but, that doesn't stop anyone of getting GUI stuff done in Haskell. Right now there are several popular bindings for graphical interfaces in Haskell, and it is amazing to see how (for example) gtk2hs supports many of the gtk-2.8 library options, and it is actually one of the few languages with support for this version of the API, according to the languages bindings list of the gtk site. So, the thing isn't that bad as many people might believe.<BR/><BR/>I do think you can get a "serious" GUI application on Haskell with the current toolkits available. It will very much depend upon thinking 'less' imperatively and more 'functional' at the end ;-)<BR/><BR/>Regards,araujohttps://www.blogger.com/profile/03804288532569108100noreply@blogger.comtag:blogger.com,1999:blog-6913397465984649777.post-4691624035179010552007-04-27T09:40:00.000-07:002007-04-27T09:40:00.000-07:00There's a problem.Say your program maintains a pre...There's a problem.<BR/><BR/>Say your program maintains a pretty deep data structure that consists of nested records. What do you do if you need to update a field somewhere deep down in <BR/>this structure in response to an event? You can't just poke at the field like in Java/any other imperative language. You need to reconstruct the entire thing. <BR/>*Very* inconvenient. <BR/><BR/>Yes, you can solve this by putting every field inside an IORef, but then you can't apply pure processing functions to the structure anymore, so you loose the functional approach.<BR/><BR/>This makes IO monad based GUI programming in Haskell very clumsy, for all but the smallest programs.<BR/><BR/>Sadly, functional reactive libraries in Haskell doesn't support more than a few of the basic widgets. Maybe this will change.<BR/><BR/>I'd rather program a GUI intensive program with a large "model" structure in Scala, than in Haskell, if it weren't for the fact that I love all other aspects of Haskell so much ;)David Waernhttps://www.blogger.com/profile/04685936983595019433noreply@blogger.comtag:blogger.com,1999:blog-6913397465984649777.post-1006866085720915992007-04-22T01:09:00.000-07:002007-04-22T01:09:00.000-07:00Alright, that makes some sense to me. Thank you fo...Alright, that makes some sense to me. Thank you for clarifying this to me.Maltehttps://www.blogger.com/profile/11235618855915052850noreply@blogger.comtag:blogger.com,1999:blog-6913397465984649777.post-86647624845115010962007-04-21T14:23:00.000-07:002007-04-21T14:23:00.000-07:00Let's say, there are just different approaches, an...Let's say, there are just different approaches, and they pretty much depend on the whole design of your code.<BR/><BR/>Himerge doesn't use any mutable state, and i assume is because of two visible characteristics on its global design:<BR/><BR/> 1 - Small functions with well defined behaviours.<BR/> 2 - A coherent data flow passing through the arguments of each functions.<BR/><BR/>If not all, i think these two points are fundamental to omit possible mutable states on the code.<BR/><BR/>One of the effects of this design, is that functions can contain many arguments (5~6), nevertheless, using the Haskell type signature, i have found this even easier to maintain than using mutable states.araujohttps://www.blogger.com/profile/03804288532569108100noreply@blogger.comtag:blogger.com,1999:blog-6913397465984649777.post-48195557086794484612007-04-21T01:26:00.000-07:002007-04-21T01:26:00.000-07:00»... and develop a whole graphical user interface ...<I>»... and develop a whole graphical user interface without mutable variables ...«</I><BR/><BR/>The gtk2hs examples I've seen so far all used IORefs for state. Is there better/cleaner general approach?Maltehttps://www.blogger.com/profile/11235618855915052850noreply@blogger.com