
Heinrich Apfelmus
In the case of HGamer3D, the sink combinator would replace the need to declare a final "wire which runs all the wires at each step". It feels a bit weird to me to have wires like guiSetPropW that perform side effects, i.e. where it makes a different whether you observe their results or not. That's a complexity where I feel that something "has been swept under the rug".
I did not review the interface of HGamer3D, mostly because it's Windows-only. But I'd like to point out that you would prefer a non-IO monad for wires. In most cases I would recommend a monad for which (>>) is commutative like a reader and/or a commutative writer. The purpose of the underlying monad is to allow some event wires to be written more cleanly. Without the monad: keyPressed :: (Monad m, Monoid e) => SDL.Keysym -> Wire e m SDL.Event SDL.Event With the monad: keyPressed :: (SDLMonad m, Monoid e) => SDL.Keysym -> Wire e m a a In particular imperative wires like guiSetPropW (or anything for which *set* is a sensible name) are simply wrong. A widget, e.g. a button, should look like this: type MyWire = WireM (Reader MyConfig) type MyEvent a = MyWire a a button :: MyEvent Button This wire takes a button configuration describing the current state of the button. Given an IsString Button instance and OverloadedStrings a GUI with a button could look like this: numberField = label >>> textField "" <|> errorLabel . "Please enter a valid number" dialog = proc _ -> do n1 <- numberField -< "Number 1" n2 <- numberField -< "Number 2" let s = n1 + n2 :: Integer label -< "Sum: " ++ show s button -< "Okay" id -< s As most event wires the button wire acts like identity when the button is pressed, so it would return back the button configuration. I hope this sheds some light onto what GUI code in Netwire /should/ (in fact /will/) look like. Greets, Ertugrul -- Not to be or to be and (not to be or to be and (not to be or to be and (not to be or to be and ... that is the list monad.