Some random thought of my own

Nick Name <[email protected]>
Newsgroups gmane.comp.lang.haskell.gui
Message-ID <[email protected]>
DISCLAIMER: I don't pretend to have had new ideas, nor that what I say
here is correct or good. It is premature to post my code here, I have
not studied everything I wanted to, but since the discussion is up and
running, I have to :)

On Wed, 5 Mar 2003 16:13:03 -0800 (PST)
David Sankel <[email protected]> wrote:

> 
>  I propose we use the GIO/Object IO style.  Does anyone
>  have any other preferred styles that I'm missing? 
>  Which style do you prefer?

There are others. First, you can define widget and combinators as purely
functional values, and really "create" widgets only in the runGUI (or
whatever you'd name it) operation.

I have a working example, which I wrote just to classify all my thougts,
in wich the simple program proposed by John Meacham looks like:

main =  do
	(w,b) <- managedButton "Bye"

	Application a <- runGUI (window (vBox [label "Hello World!",w]))

	processOutput_ (buttonClicked b) 
                           [putInput (buttonLabel b) "Goodbye",
                            putInput a ()]

managedButton :: String -> IO (Widget,Button)
button :: String -> Widget
label :: String -> Widget

...and so on. I wrote it to test an idea I have about changing the
state, note how the Widget type is purely functional (it encapsulates
the IO needed to create the widget). I attach my code, wich is for
Gtk2hs, in case someone wants to read it.

Let's come back to the topic. I apologize for my bad english, as usual,
and for the length of this e-mail.


=======
1. How is the local state of a widget changed?
   
   Basically, the world is divided between people that like monadic   
operations, and people that prefer streams. Manuel Chakravarty in his
"Ports" library combines the two, even if he is more biased to streams.
When it's time to choose between two different approaches, which prove
both useful, I prefer when I can have both!

We can do a more fine-grained work by separating the read and write
operations (thus avoiding a runtime error implementing the write
operation of read-only properties). This leads to the following
definition for a variable:

data Input a = Input { putInput :: a -> IO () }

data Output a = Output { readOutput :: IO a,
		         waitOutput :: IO a,  -- wait for a state change
		         listenOutput :: IO [a] }

data Var a = Var { varInput :: Input a,
		   varOutput :: Output a }

We can define in a purely functional way the map operation on an output,
and many transformations on inputs and outputs, as it's done in FRAN;
(There are issues to consider, such as "closing" the Var; I leave it for
tomorrow and for more expert people; also, someone willing to speak
about arrows and Var?).

Using this idea, an handler for a button has type "Output ()", or at
least contains this type.

You can also install a callback on state changes, with the operations:

  onOutput :: Output a -> (a -> IO b) -> IO ()
  onOutput o m = forkIO ( listenOutput o >>= mapM_ m) >> return ()
 
  onVar = onOutput . varOutput

(BTW, threads in GHC *are* lightweight! I tested listening to thousands
of Vars simultaneously without troubles on a celeron some month ago)

And, besides, separating input and output you can give a simple
interface to many things, for example input devices are "Output"s from
the point of view of the application.

NOTE:
With Ports, or Vars or Attrs, one can easily make a variable persistent.
I think this hasn't been spotted, but deserves more attention!


=====
2. How is a widget created?
Everyone seems to agree on

      createSomething :: SomethingConfiguration -> IO Something

but this clutters the code with many unneeded monadic operations. We   
can use data constructors when needed, or postpone the creation in a   
"runGUI" function and just compose the needed actions: notice how  
readable is


       runGUI (window (vBox [label "Hello World!",w])

due to the absence of monadic operators where they are not needed, if
compared to a standard monadic sequence.

In "managedButton" (the creation of w), I think monadic operator ARE
needed because we need to create an "entaglement" between the button
data and the IO operation that will create it, but I am not completely
sure.

=====
3. How is the configuration data passed to a widget? This opens many
questions, and surely many other that I don't mention here.

   - We could have two constructors for a button, one "a la GIO" and one
     with standard function syntax, wich is more readable in some cases.
        Example:
   
          button "Hi all"

       versus
 
          button [label=:"Hi all"]
       
       Of course, this is not Daan Leijen's fault: it's difficult to    
   handle defaults to avoid entering ten or twelve configuration       
parameters. In my example, I don't care about a button being also       
a widget with size, for example. So I propose to give both the       
interfaces, one with only basic options and a functional form,      
another, more complex, like the one in GIO or with records.

   - Some subtyping trick with multiparameter type classes can make the
     operator =: accept properties for a generic, and apply them to a
     button, I think.

   - We need to consider the loading from resource files as a     
constructor, not everything is pragmatic. I think this is      not a big
issue.

   - I would like to know more about named widgets and their use.

   - We could just use record types, filling undefined fields with     
defaults in the constructor. This approach can easily live side by     
side with the GIO one.

   - We could just use implicit parameters, but I don't think this would
     feel comfortable.

=====

I hope someone is interested...

Vincenzo
GUI.hs (application/octet-stream, 2.9 KB) - not displayed
Var.hs (application/octet-stream, 8.4 KB) - not displayed
Makefile (application/octet-stream, 236 B) - not displayed
Main.hs (application/octet-stream, 346 B) - not displayed
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.