
Good morning, I had a look at GIO and my first impression is that it's interface is nice for application writers as well as for GUI toolkit implementors. What appeals to me (having a low-level GUI binding, gtk2hs) is that binding to such an API is actually worthwhile (i.e. it's more than just renaming functions). Some questions, comments and critics about GIO: 1. Using IO (). All functions use the IO () monad unlike the proposed port of Object IO which introduces GUI (). I think this decision is the Right Thing (tm). (If other libraries insist of having their own Monad then it can become impossible to mix these two libraries.) 2. The := operator. The =: function should say "assign to this property". Is seems to be the wrong way round. Is it possible to use the constructor := , or is this conceptionally difficult? 3. The global mechanism to change widgets. The set and get functions define a single mechanism to modify UI components. This seems very neat to me. This is implemented via Haskell classes. The distribution between functions and classes seem to be a little ad-hoc, though. The two extremes are probably: a) Define a class for every function and make each widget which supports this function an instance of this class. Or b) define a class for every widget and make every function this widget has a member of this class. Why do you use this mixed approach (e.g. class Able, Select, SingleSelect,...)? 4. Educational vs Professional. When browsing the drawing primitives, I noticed that you abandon the explicit use of Pens (i.e. graphics contexts, GCs). GCs are used for performance reasons as passing color, thickness etc. each time is said to be inefficient. This is probably just one example begging the general question: Are we aiming for an API which is easy to use or which enables professional applications? It's the latter, right? So far, there is probably more to debate, but I have to get some work done :-), Axel.

Dear Axel,
I had a look at GIO and my first impression is that it's interface is nice for application writers as well as for GUI toolkit implementors.
Thanks! remember though that GIO is heavily influenced by Koen Claessens Yahu lecture notes.
2. The := operator. The =: function should say "assign to this property". Is seems to be the wrong way round. Is it possible to use the constructor := , or is this conceptionally difficult?
Great plan. I tried it in my upcoming wxWindows-GIO library, and found that I needed existential types. Not a problem since we are GHC dependent anyway :-) (well, maybe not, NHC is getting really good these days). Anyway, I defined: data Attr w a = Attr (w -> IO a) (w -> a -> IO ()) -- getter and setterdata Prop w = forall a. (:=) (Attr w a) a -- := is a constructorset :: w -> [Prop w] -> IO ()set w props = mapM_ setProp props where setProp ((Attr getter setter) := x) = setter w xget :: w -> Attr w a -> IO aget w (Attr getter setter) = getter w -- example of an attribute, works for any kind of (wxWindows) Frametitle :: Attr (Frame a) Stringtitle = Attr (\w -> w # frameGetTitle) (\w x -> w # frameSetTitle x)...gui = do ... set frame [title := "hi there"] Really nice!, thanks for sparking the idea. Nice application of existential types too.
3. The global mechanism to change widgets. The set and get functions define a single mechanism to modify UI components. This seems very neat to me.
I like that too, makes it all a bit more natural.
This is implemented via Haskell classes. The distribution between functions and classes seem to be a little ad-hoc, though. The two extremes are probably: a) Define a class for every function and make each widget which supports this function an instance of this class. Or b) define a class for every widget and make every function this widget has a member of this class. Why do you use this mixed approach (e.g. class Able, Select, SingleSelect,...)?
Yeah, I don't like it either. I think that for the new wxWindows version I am going to take an extreme route (especially since I am generating the definitions mostly automatically (about 256 classes with 2500 methods resulting in 18000 lines of generated haskell marshaling code :-)) I think that the best way would be to add a class for each attribute. Something like: class AttrTitle w where title :: Attr w Stringinstance AttrTitle (Frame a) where --every Frame derived object has a title title = ...The only problem is that we need again GHC extensions... but I think that most compilers supports this kind of definition. The good part is that it also becomes easier to define your own kind of controls build from primitive controls that are indistinguishable from the primitive ones (by providing your own attribute instances)
4. Educational vs Professional. When browsing the drawing primitives, I noticed that you abandon the explicit use of Pens (i.e. graphics contexts, GCs). GCs are used for performance reasons as passing color, thickness etc. each time is said to be inefficient. This is probably just one example begging the general question: Are we aiming for an API which is easy to use or which enables professional applications? It's the latter, right?
Regarding the drawing primitives in GIO: I already feel that GIO is too heavy-weight with mutable variables etc. I can't see how to avoid it though. Fortunately, the wxWindows version will get rid of that as almost all the state is stored on the wxWindows side. I think that TkGofer also took advantage of the same kind of thing, since Tcl/Tk stores almost all necessary state. Regarding the Educational vs Professional: It would be the best if it is suitable for both: that is, it shouldn't be too hard to start with something and there should be some reasonable high-level functions for educational use. However, we should also make sure that the low-level stuff is always available (and rich enough). I don't know whether GIO takes the correct approach here... don't forget that it is still just an experimental thing. With the wxWindows library things are a bit easier since one can always use the bare library itself without the fancy attributes, and there is just so much functionality there that everyone can be satisfied. This is btw. on of my main worries for Port. Since it is yet another "create our own library", it may never become rich enough for professional use, or may never even become bug-free or maintained enough. In that sense it would 'professionally' be better to build on other people's libraries like GTK, Qt or wxWindows. However, 'educationally', one may be better off using a more light-weight approach like SOEgraphics, or Port. All the best, Daan.
So far, there is probably more to debate, but I have to get some work done :-), Axel.
_______________________________________________ GUI mailing list GUI@haskell.org http://www.haskell.org/mailman/listinfo/gui

Warning about the use of (:=): This symbol has been proposed by John Hughes for use in some future version of Haskell to distinguish monomorphic and polymorphic `let` constructs. (See, for example, http://www.math.chalmers.se/~rjmh/Globals.ps , section 6.) You might prefer to choose a different symbol, such as (:==) or (::=). Dean Daan Leijen wrote:
2. The := operator. The =: function should say "assign to this property". Is seems to be the wrong way round. Is it possible to use the constructor := , or is this conceptionally difficult?Great plan. I tried it in my upcoming wxWindows-GIO library, and foundthat I needed existential types. Not a problem since we are GHCdependent anyway :-) (well, maybe not, NHC is getting really good these days).Anyway, I defined:
data Attr w a = Attr (w -> IO a) (w -> a -> IO ()) -- getter and setter
data Prop w = forall a. (:=) (Attr w a) a -- := is a constructor
set :: w -> [Prop w] -> IO () set w props = mapM_ setProp props where setProp ((Attr getter setter) := x) = setter w x
get :: w -> Attr w a -> IO a get w (Attr getter setter) = getter w
-- example of an attribute, works for any kind of (wxWindows) Frame title :: Attr (Frame a) String title = Attr (\w -> w # frameGetTitle) (\w x -> w # frameSetTitle x)
...
gui = do ... set frame [title := "hi there"]
Really nice!, thanks for sparking the idea. Nice application of existential types too.

Warning about the use of (:=): This symbol has been proposed by John Hughes for use in some future version of Haskell to distinguish monomorphic and polymorphic `let` constructs. (See, for example, http://www.math.chalmers.se/~rjmh/Globals.ps , section 6.) You might prefer to choose a different symbol, such as (:==) or (::=). Thanks for mentioning this. However, (:=) is a rather attractive constructor to use and I wonder if a monomorphic binding is used enoug to justify taking another operator away. It might be better after all to have a family of "let" bindings in a future haskell: let -- lazy bindinglet! -- strict bindinglet$ -- speculative binding (ie. try operationally strictly but maintain lazy semantics)let# -- monomorphic binding ?... -- Daan. Dean Daan Leijen wrote: > 2. The := operator. > The =: function should say "assign to this property". Is seems to be the > wrong way round. Is it possible to use the constructor := , or is this > conceptionally difficult?Great plan. I tried it in my upcoming wxWindows-GIO library, and foundthat I needed existential types. Not a problem since we are GHCdependent anyway :-) (well, maybe not, NHC is getting really good these days).Anyway, I defined: data Attr w a = Attr (w -> IO a) (w -> a -> IO ()) -- getter and setterdata Prop w = forall a. (:=) (Attr w a) a -- := is a constructorset :: w -> [Prop w] -> IO () set w props = mapM_ setProp props where setProp ((Attr getter setter) := x) = setter w xget :: w -> Attr w a -> IO a get w (Attr getter setter) = getter w-- example of an attribute, works for any kind of (wxWindows) Frame title :: Attr (Frame a) String title = Attr (\w -> w # frameGetTitle) (\w x -> w # frameSetTitle x)...gui = do ... set frame [title := "hi there"] Really nice!, thanks for sparking the idea. Nice application of existential types too.

On Wed, 12 Feb 2003, Daan Leijen wrote:
[Dean wrote:]
Warning about the use of (:=): This symbol has been proposed by John Hughes for use in some future version of Haskell to distinguish monomorphic and polymorphic `let` constructs. (See, for example, http://www.math.chalmers.se/~rjmh/Globals.ps , section 6.) You might prefer to choose a different symbol, such as (:==) or (::=).
Thanks for mentioning this. However, (:=) is a rather attractive constructor to use
Yes, indeed.
and I wonder if a monomorphic binding is used enoug to justify taking another operator away.
The choice between polymorphism and sharing is fundamental enough that I think it's worth an operator symbol (*). Of course it doesn't need to be (:=), but it shouldn't be too weird, either. [(*) The use in a binding construct is pure syntax, not really an operator. In fact, I think the same symbol could (though probably not should) be used for binding and as a general-use operator.]
It might be better after all to have a family of "let" bindings in a future haskell: let -- lazy binding let! -- strict binding let$ -- speculative binding (ie. try operationally strictly but maintain lazy semantics) let# -- monomorphic binding ?...
That proposal doesn't work, for several related reasons: 1. A `let` may introduce multiple bindings. It's undesirable that all such bindings be required to be of the same sort. 2. The same binding choices apply also to `where`. 3. The same binding choices apply also at the top level, where there's no `let` or `where` keyword to decorate. In summary, it's much cleaner to indicate the binding choice with the symbol. -- Dean

On Wed, 12 Feb 2003, Daan Leijen wrote:
Warning about the use of (:=): This symbol has been proposed by John Hughes for use in some future version of Haskell to distinguish monomorphic and polymorphic `let` constructs. (See, for example, http://www.math.chalmers.se/~rjmh/Globals.ps , section 6.) You might prefer to choose a different symbol, such as (:==) or (::=).
Thanks for mentioning this. However, (:=) is a rather attractive constructor to use and I wonder if a monomorphic binding is used enoug to justify taking another operator away.
It might be better after all to have a family of "let" bindings in a future haskell:
let -- lazy binding let! -- strict binding let$ -- > speculative binding (ie. try operationally strictly but maintain lazy
semantics) let# -- monomorphic binding ?...
-- Daan.
The trouble with this idea is that let is associated with a BINDING GROUP, not with an individual binding -- and indeed, some binding groups (e.g. the top level!) have no associated let. You really want to be able to mark, say, one top-level binding as monomorphic. So the right place to attach this information is to the syntax of the binding itself -- that is, the equals sign. John

On Mon, Feb 10, 2003 at 11:59:16PM +0100, Daan Leijen wrote:
Dear Axel,
I had a look at GIO and my first impression is that it's interface is nice for application writers as well as for GUI toolkit implementors.
Thanks! remember though that GIO is heavily influenced by Koen Claessens Yahu lecture notes.
2. The := operator. The =: function should say "assign to this property". Is seems to be the wrong way round. Is it possible to use the constructor := , or is this conceptionally difficult?
Great plan. I tried it in my upcoming wxWindows-GIO library, and found that I needed existential types. Not a problem since we are GHC dependent anyway :-) (well, maybe not, NHC is getting really good these days). Hm, ok then I see a good reason not to use := . I think it's better to stick to Haskell 98 features. But I don't feel very strongly about this. If := is going to be a reserved symbol one day, then we should perhaps not use it.
So you're now doing a binding to wxWindows. May I criticise?! wxWindows tries to give a native look by using the native API. It seems to do a good job. But when it comes to native feel, I wonder if this full-fledged API can abstract away the semantic differences of the platforms. I guess there is always need for a serious application to implement certain bits of the GUI directly with the native API to bridge this semantic gap. Can you use wxWindows for the standard GUI stuff and still use the native API for some functionality? If yes, then this is what - I think - we are aiming for. In that case I might consider dumping my gtk2hs binding and help you with a binding to wxWindows.
This is implemented via Haskell classes. The distribution between functions and classes seem to be a little ad-hoc, though. The two extremes are probably: a) Define a class for every function and make each widget which supports this function an instance of this class. Or b) define a class for every widget and make every function this widget has a member of this class. Why do you use this mixed approach (e.g. class Able, Select, SingleSelect,...)?
Yeah, I don't like it either. I think that for the new wxWindows version I am going to take an extreme route (especially since I am generating the definitions mostly automatically (about 256 classes with 2500 methods resulting in 18000 lines of generated haskell marshaling code :-))
I think that the best way would be to add a class for each attribute. Something like: class AttrTitle w where title :: Attr w Stringinstance AttrTitle (Frame a) where --every Frame derived object has a title title = ...The only problem is that we need again GHC extensions... but I think that most compilers supports this kind of definition. The good part is that it also becomes easier to define your own kind of controls build from primitive controls that are indistinguishable from the primitive ones (by providing your own attribute instances) Why not the other extreme route: Having one class for each widget? The name overlap is minimal I think and it is much easier to understand.
4. Educational vs Professional. When browsing the drawing primitives, I noticed that you abandon the explicit use of Pens (i.e. graphics contexts, GCs). GCs are used for performance reasons as passing color, thickness etc. each time is said to be inefficient. This is probably just one example begging the general question: Are we aiming for an API which is easy to use or which enables professional applications? It's the latter, right?
Regarding the drawing primitives in GIO: I already feel that GIO is too heavy-weight with mutable variables etc. I can't see how to avoid it though. Fortunately, the wxWindows version will get rid of that as almost all the state is stored on the wxWindows side. If let wxWindows handle the applications state (via StablePtr), how are you going to make that type safe? Mulit-parameter classes? I think the common GUI API should be in Haskell 98.
Regarding the Educational vs Professional: It would be the best if it is suitable for both: that is, it shouldn't be too hard to start with something and there should be some reasonable high-level functions for educational use. I think we should go for a purely professional API. You can always put a simple layer on to of it, but not vice versa. Using colors and fonts directly and avoiding graphics contexts is wrong IMHO.
So far, there is probably more to debate, but I have to get some work done :-), One point that came up in our Departmental FP group was that the way Object I/O identifies objects is superior to GIOs. They create an identifier with a special monadic function rId. The you construct an algebraic data type which specifies you GUI. GIO on the otherhand uses functions to create widgets. You use these widgets values to pass them to other widgets (e.g. containers). Note that in both settings it is possible to put one button into two different container. But only in the Object I/O approach this can easily be detected (you keep all created rIds in an array and see if they have been used yet). In GIO you would need to traverse the whole widget tree of all windows to determine if a button is already inserted somewhere else.
So much for now, Axel.

--- Axel Simon
Note that in both settings it is possible to put one button into two different container. But only in the Object I/O approach this can easily be detected (you keep all created rIds in an array and see if they have been used yet). In GIO you would need to traverse the whole widget tree of all windows to determine if a button is already inserted somewhere else.
I don't know how this is made with wxWindows, but in GIO for Port the container for the button is specified as argument to "button" function. Once created the button cann't change its parent. I the trouble here is with "layout" attribute. Its setter should chech when all widget inside the Layout data are assigned to the target widget. I suppose that with wxWindows the case is similar with the Port. Krasimir __________________________________________________ Do you Yahoo!? Yahoo! Shopping - Send Flowers for Valentine's Day http://shopping.yahoo.com

On Tue, Feb 11, 2003 at 03:24:19PM -0800, Krasimir Angelov wrote:
--- Axel Simon
wrote: Note that in both settings it is possible to put one button into two different container. But only in the Object I/O approach this can easily be detected (you keep all created rIds in an array and see if they have been used yet). In GIO you would need to traverse the whole widget tree of all windows to determine if a button is already inserted somewhere else.
I don't know how this is made with wxWindows, but in GIO for Port the container for the button is specified as argument to "button" function. Once created the button cann't change its parent.
Oh, ok. So you specify the parent of a widget when you create it, thus a widget can never have two parents. Makes sense. In that case I opt for the Yaho/GIO approach instead of the algebraic data structure approach (Object I/O).
The trouble here is with "layout" attribute. Its setter should chech when all widget inside the Layout data are assigned to the target widget. I suppose that with wxWindows the case is similar with the Port. I am not sure I understand. Would it solve the problem if "layout" isñ a read-only attribute (like Sven Panne suggested)?
Axel.

Axel Simon wrote:
So you're now doing a binding to wxWindows. May I criticise?!
wxWindows tries to give a native look by using the native API. It seems to do a good job. But when it comes to native feel, I wonder if this full-fledged API can abstract away the semantic differences of the platforms. I guess there is always need for a serious application to implement certain bits of the GUI directly with the native API to bridge this semantic gap. Can you use wxWindows for the standard GUI stuff and still use the native API for some functionality? If yes, then this is what - I think - we are aiming for. In that case I might consider dumping my gtk2hs binding and help you with a binding to wxWindows.
I am not a wxWindows expert but I got the impression that very serious applications were written in wxWindows and that it may thus be more than enough for the humble Haskell programmer. I also saw some definitions that were commented with "(only has effect on platform XXX)" and some functions that gave access to a platform specific "handle".
Why not the other extreme route: Having one class for each widget? The name overlap is minimal I think and it is much easier to understand.
You are right. The drawback is that certain (object) classes have the same methods and you would get into trouble if you try to generate one (type) class for each widget (kind) class. However, I found out that attributes weren't regular enough for automatic generation and I am thinking about writing them by hand, in which case your proposed approach is probably better.
If let wxWindows handle the applications state (via StablePtr), how are you going to make that type safe? Mulit-parameter classes? I think the common GUI API should be in Haskell 98.
You misunderstood me. The wxWindows C++ objects maintain state. If I can set something, I can always also get the value back. With Port this is not always the case and you have to 'remember' an attribute value also on the haskell side with a mutable variable. This means that with wxWindows I can get away with just using plain stable pointers to C++ objects without any mutable variables in Haskell.
One point that came up in our Departmental FP group was that the way Object I/O identifies objects is superior to GIOs. They create an identifier with a special monadic function rId. The you construct an algebraic data type which specifies you GUI. GIO on the otherhand uses functions to create widgets. You use these widgets values to pass them to other widgets (e.g. containers). Note that in both settings it is possible to put one button into two different container. But only in the Object I/O approach this can easily be detected (you keep all created rIds in an array and see if they have been used yet). In GIO you would need to traverse the whole widget tree of all windows to determine if a button is already inserted somewhere else.
I wouldn't say superior as both are implementable in terms of each other. It is just another approach. As Krasimir already said, the only point where GIO can go wrong is when trying to lay out a button in a widget that is not its parent. This can also easily be detected at runtime (check if the parent is the current widget) -- there is no need to traverse the widget trees. Furthermore, I really like the strong typed connection between a widget and a haskell identifier. The real drawbacks are in my opinion: 1) the need to specifiy a parent (w) when creating a control (ie. b <- button [] w) this hinders abstraction. 2) layout is not statically checkable, you can put controls in the wrong window. Now, ObjectIO "solves" these above problems by having an algebraic data type that describes the gui and layout. This structure is than interpreted by the parent that creates the controls and lays them out (using GIO like calls). To let controls communicate with each other, you are forced to use generated Id's instead of normal identifiers. By doing that, you also loose things: you need to lump all control attributes together in one big data type for example. For libraries as wxWindows this leads to a really huge data type. Or you can specify attributes that are ignored / not applicable for a certain window/control. Now, I don't know yet the correct solution for this dilemma. Krasimir uses an ObjectIO like approach of specifying the GUI but his function returns a list of identifiers for each element. By binding them lazily, the controls can refer to each other before being actually created. It goes something like this:
~(b1 :+: b2) <- (button1 <<< button2)
All the best, Daan.
So much for now, Axel.
_______________________________________________ GUI mailing list GUI@haskell.org http://www.haskell.org/mailman/listinfo/gui

Axel Simon wrote:
Hm, ok then I see a good reason not to use := . I think it's better to stick to Haskell 98 features. But I don't feel very strongly about this.
Well, but I do. :-) Granted, ":=" looks better than "=:", but losing H98 compliance just for a small cosmetic thing is rather bad IMHO. After a look at Yahu/GIO I decided to use set/get/=: in 'HOpenGL: The Next Generation' :-) instead of the current rather ad-hoc stuff inherited from C. OpenGL is a state machine and uses state variables rather extensively, and these map very nicely to Haskell using the functions above. The only concept Yahu/GIO is missing is the distinction between read-only, write-only, and "normal" state variables, so I've adapted it slightly, see: http://cvs.haskell.org/cgi-bin/cvsweb.cgi/fptools/libraries/OpenGL/Graphics/Rendering/OpenGL/GL/StateVariable.hs?rev=1.1&content-type=text/x-cvsweb-markup My question is: The attribute/property/state variable pattern seems to be a more universal concept than I initially thought, so it might be a good idea to have support for this in the standard libraries. But exactly how is not completely clear to me, e.g. GIO uses an additional type variable (for the kind of widget). Any ideas and/or suggestions? OK, modules like this look rather obvious and small, so why should we standardize it at all? Linguistic abstraction! Having a set of standard functions/operators available for a common task is always a good idea, it makes other people's programs (and old ones written by oneself :-) much easier to read. Embedding a domain specific language into Haskell by defining myriads of home-grown operators is often a fine way of obfuscating a program (Prolog programs are often not much better in this respect, BTW).
If := is going to be a reserved symbol one day, then we should perhaps not use it. [...]
I wasn't aware of that, but it's just another reason... Cheers, S.

After a look at Yahu/GIO I decided to use set/get/=: in 'HOpenGL: The
Good plan. Since wxWindows has an openGL canvas widget, we may want to work more closely on this in the future :-)
My question is: The attribute/property/state variable pattern seems to be a more universal concept than I initially thought, so it might be a good idea to have support for this in the standard libraries. But exactly how is not completely clear to me, e.g. GIO uses an additional type variable (for the kind of widget). Any ideas and/or suggestions?
It certainly seems more generally applicable than just gui's. However, I would suggest a small change to your approach where you define a getter and setter class. Instead, I would focus on "attributes". That is, "get" and "set" work universally on attributes. Suppose for now that we don't use a write/read only distinction. An attribute has both a type "a" and a thing that it belongs to "w". I wonder why the "thing it belongs to" is absent from your approach as it seems quite fundamental to me. It allows you for example to organise the attributes in type classes and re-use the same attribute name for different kind of things. data Attr w a = Attr{ getter :: w -> IO a, setter :: a -> w -> IO () }get :: Attr w a -> w -> IO aget attr w = (getter attr) wFor, setting, we use properties -- attributes that are already associated with a value. This allows us to both a bunch of them in lists. data Prop w = forall a. Prop (Attr w a) a -- or even: forall a. (Attr w a) := a(=:) :: Attr w a -> a -> Prop wattr =: x = Prop attr xOr, if you stick to Haskell98: data Prop w = Prop (w -> IO ())(=:) :: Attr w a -> a -> Prop wattr =: x = Prop ((setter attr) x)And set works like: set :: [Prop w] -> w -> IO ()set props w = mapM_ (\(Prop setter) -> setter w) propsNow, regarding openGL with state variables, you would make attributes that work on those, for example: value :: Attr (IORef a) avalue = Attr (getIORef) (setIORef)So, even openGL will assign attributes to certain kind of things. Furthermore, you can still make a read/write distinction by putting "get" and ":=" in classes as you do: class Readable attr where get :: attr w a -> w -> IO aclass Writable attr where (=:) :: attr w a -> a -> Prop winstance Readable Attr where ...instance Writable Attr where ...But I am personally a bit hesitant to do this as it might give rise to rather complex error messages -- but only experience will show whether this is actually the case.
OK, modules like this look rather obvious and small, so why should we standardize it at all? Linguistic abstraction! Having a set of standard functions/operators available for a common task is always a good idea, it makes other people's programs (and old ones written by oneself :-)
I totally agree. I hope though that we can find a really general abstraction that will also work for the GUI's or otherwise it doesn't make much sense. Therefore, i am quite curious if the approach that is focused on "Attributes" as sketched in this mail will also work for openGL. All the best, Daan.
much easier to read. Embedding a domain specific language into Haskell by defining myriads of home-grown operators is often a fine way of obfuscating a program (Prolog programs are often not much better in this respect, BTW).
If := is going to be a reserved symbol one day, then we should perhaps not use it. [...]
I wasn't aware of that, but it's just another reason...
Cheers, S.
_______________________________________________ GUI mailing list GUI@haskell.org http://www.haskell.org/mailman/listinfo/gui

Daan Leijen wrote:
[...] An attribute has both a type "a" and a thing that it belongs to "w". I wonder why the "thing it belongs to" is absent from your approach as it seems quite fundamental to me.
Of course there is a "thing it belongs to" for state variables in OpenGL, too: It's the current rendering context (= the big, fat OpenGL state machine), but it is implicit in all OpenGL calls. Handling the context is beyond OpenGL's scope and normally handled by a GUI toolkit, e.g. GLUT. You could do this e.g. under X11 with GLX calls like glXMakeContextCurrent, which associates a context with the current OS thread (Hello, FFI list! :-), but this is rather unusual. You normally have a single context per window, and that's it. Furthermore, switching an OpenGL context could be rather heavyweight, as it potentially involves a lot of "real world" state changes on your graphics card (reprogramming texture units, swapping of display lists, flushing rendering pipelines, etc.). So this implicitness was a rather intentional design choice when the OpenGL API was created and should not be re-introduced artificially afterwards.
It allows you for example to organise the attributes in type classes and re-use the same attribute name for different kind of things.
Hmmm, For the reason stated above, I don't think that there will be type classes in HOpenGL similar to the usual "has a label" stuff in GUI bindings.
[ some Haskell code for Attr, get, Prop, (=:), and set omitted ... ]
That's basically what Graphics.UI.GIO.Attributes does, or did I miss something?
Now, regarding openGL with state variables, you would make attributes that work on those, for example:
value :: Attr (IORef a) a value = Attr (getIORef) (setIORef)
So, even openGL will assign attributes to certain kind of things.
Nope, state variables in OpenGL have nothing to do with IORefs or something similar, they are entities from the current context (= state machine), and are not mirrored on the Haskell side. If they can be set, there is an OpenGL call to do that, and if they can be read, there is an OpenGL call retrieving that part of the state. If one or both of the calls are missing from the API, there is a very good reason for this. The "w" in GIO's API would always be "()" in HOpenGL, and should therefore be hidden from the latter API. Otherwise the types and calls would look rather strange, and people would start asking what this omnipresent "()" should mean. In types the "()" could be hidden by appropriate "type" definitions, in function calls the extra argument can be supplied by a wrapper function.
Furthermore, you can still make a read/write distinction by putting "get" and ":=" in classes as you do:
class Readable attr where get :: attr w a -> w -> IO a
class Writable attr where (=:) :: attr w a -> a -> Prop w
instance Readable Attr where ... instance Writable Attr where ...
You can't make a distinction with a single Attr type, you need different ones for readable, writeable and r/w attributes. It's crucial IMHO that you get a type error when you e.g. apply "get" to a write-only attribute.
But I am personally a bit hesitant to do this as it might give rise to rather complex error messages [...]
Better a complex error message at compile time than a simple one at runtime. :-) Seriously, I don't expect real problems if we stay within H98.
[...] Therefore, i am quite curious if the approach that is focused on "Attributes" as sketched in this mail will also work for openGL.
Despite my comments above, I think there is common ground: Doing some trivial impedance matching (nuking the "()") won't pose real problems in HOpenGL's case, so the question is: Can you fit the read/write distinction into GIO? BTW, I had a closer look at GLUT and OpenAL (something I really like to write a binding for, too) and found that the concepts in question would be rather beneficial for a Haskell API. OTOH, this should have been expected, because those APIs are closely modeled after OpenGL. Cheers, S.

The getter and setter abstractions are really more universal concept than Attr in GIO and StateVariable in HOpenGL. The get and set functions are not limited to IO monad and can be implemented for many others monad types. Unfortunately proper implementation requires functional dependencies. The attached module contains definitions for get and set functions for IO, ST, Reader, ReaderT, State, StateT, RWS and RWST monads. The idea is that each monad can maintains some kind of state and the corresponding Attr type gives access to some part of the state. The good example is the StateAttr with State monad. Example: data Point = Point {x :: Int, y :: Int} attrX :: StateAttr Point Int attrX = StateAttr x (\v p -> p{x=v}) attrY :: StateAttr Point Int attrY = StateAttr y (\v p -> p{y=v}) move :: Int -> Int -> State Point Int move vx vy = do x <- get attrX attrX =: x+vx y <- get attrY attrY =: y+vy I propose to standardize this concept and add Attr module to the GHC base package. Cheers, Krasimir __________________________________________________ Do you Yahoo!? Yahoo! Shopping - Send Flowers for Valentine's Day http://shopping.yahoo.com

Krasimir Angelov wrote:
[...] Unfortunately proper implementation requires functional dependencies.
Hmmm, this is really a bit unfortunate, because I wanted to stay within the realms of Haskell 98 for HOpenGL. GHC and Hugs support this extension, but NHC98 doesn't even have MPTC, IIRC. But we'll always have #ifdef... :-] Another issue is the quality of the error messages, but after a little experimentation I found them quite bearable.
The attached module contains definitions for get and set functions for IO, ST, Reader, ReaderT, State, StateT, RWS and RWST monads. The idea is that each monad can maintains some kind of state and the corresponding Attr type gives access to some part of the state.
Cool! Only a few minor points: * It's a bit strange that a class with a "get" method is called "Readable". "HasGetter" or "Gettable" would look more consistent to me, but I'm not a native speaker. * A list version of (=:) is missing (called "set" in GIO/HOpenGL). But even its type wouldn't be clear to me given this general version of (=:). Hmmm... * Some people have already mentioned that "=:" may be a bit misleading, so a different operator may be appropriate. But not ":=" at the price of even more non-standard typing!
[...] I propose to standardize this concept and add Attr module to the GHC base package.
That was my intention. We should probably move this thread to the libraries list and continue discussion there (e.g. naming, where should the classes and instances reside in the module hierarchy, etc.). Krasimir: Do you want to propose your Attr module there (without the GIO/HOpenGL stuff, of course)? It's your baby, after all... Cheers, S.

--- Sven Panne
* It's a bit strange that a class with a "get" method is called "Readable". "HasGetter" or "Gettable" would look more consistent to me, but I'm not a native speaker.
I just follow definitions given from Daan: --- Daan Leijen wrote:
Furthermore, you can still make a read/write distinction by putting "get" and ":=" in classes as you do:
class Readable attr where get :: attr w a -> w -> IO a class Writable attr where (=:) :: attr w a -> a -> Prop w
But maybe you are right HasGetter and HasSetter are more adequate names. I don't have any preferences about names.
* A list version of (=:) is missing (called "set" in GIO/HOpenGL). But even its type wouldn't be clear to me given this general version of (=:). Hmmm...
With new implementation the HOpenGL's set function is just well known sequence_ function from the standard prelude. The GIO's set function correspond to setp function from the Attr module.
That was my intention. We should probably move this thread to the libraries list and continue discussion there (e.g. naming, where should the classes and instances reside in the module hierarchy, etc.).
Well! I expect future discussion in the libraries@haskell.org. I propose to extract the type classes in the new module (maybe Control.Monad.Attributes) and after that to add attribute types along with their instances to modules which defines corresponding monads.
Krasimir: Do you want to propose your Attr module there (without the GIO/HOpenGL stuff, of course)? It's your baby, after all...
Of course. The attributes can be used in much more places than in GIO and HOpenGL. The good example is HToolkit Draw monad. There are many functions like (get/set)PenColor, (get/set)PenSize which can be replaced with attributes of type PenAttr. Cheers, Krasimir __________________________________________________ Do you Yahoo!? Yahoo! Shopping - Send Flowers for Valentine's Day http://shopping.yahoo.com

Krasimir Angelov wrote:
[...] Well! I expect future discussion in the libraries@haskell.org. I propose to extract the type classes in the new module (maybe Control.Monad.Attributes) and after that to add attribute types along with their instances to modules which defines corresponding monads. [...]
Just some last remarks before we *really* move this thread to the libraries list: * Is there a way to fit your proposal into the existing Control.Monad.* hierarchy by splitting MonadState into a read and a write part? * Can we merge this somehow with Hughes' RefMonad? (http://www.math.chalmers.se/~rjmh/Globals.ps) * The need for the functional dependencies is not 100% clear to me. * Do we really need MPTC or can we get by with constructor classes somehow? This is a question I'm asking me from time to time in different contexts, too. Due to a lack of time, I haven't spent much time thinking about these issues for myself, but I think they should be clarified. Cheers, S.
participants (6)
-
Axel Simon
-
Daan Leijen
-
Dean Herington
-
John Hughes
-
Krasimir Angelov
-
Sven Panne