Tuesday, 15 July 2014

gtk - How can I reduce the number of arguments I have to pass around in Haskell? -



gtk - How can I reduce the number of arguments I have to pass around in Haskell? -

i'm getting speed in haskell, trying gui toolgit usable, etc. followed basic tutorial on using glade create simple gui app , i'm trying modularize it. in particular, wanted leverage functions instead of doing in main. first thing did create separate functions accessing buttons , associating code executed when buttons clicked. works fine if @ code below, have carry entire glade xml "variable" around me. realize don't global in haskell seems me there has improve mechanism rather carrying every single variable around in functions. in oo world, xml stuff instance variable in class implicitly available everywhere. what's "right" way in haskell world?

module main (main) import graphics.ui.gtk import graphics.ui.gtk.glade getbutton :: gladexml -> string -> io button getbutton gladexml buttonname = xmlgetwidget gladexml casttobutton buttonname onbuttonclick :: gladexml -> string -> [io a] -> io () onbuttonclick gladexml buttonname codesequence = abutton <- getbutton gladexml buttonname _ <- onclicked abutton $ -- run sequence of operations when user clicks sequence_ codesequence homecoming () loadgladefile :: filepath -> io (maybe gladexml) loadgladefile filename = g <- xmlnew filename homecoming g main :: io () main = _ <- initgui -- setup -- load glade xml file xml <- loadgladefile "tutorial.glade" -- create main window (everything within created too) window <- xmlgetwidget xml casttowindow "window1" -- define when quit _ <- ondestroy window mainquit -- show wondow widgetshowall window -- associate onclick event button onbuttonclick xml "button1" [putstrln "hello, world"] -- off go maingui

this suggestion augustss' comment. thoroughly untested, started:

import control.applicative import control.monad import control.monad.trans import control.monad.trans.reader import graphics.ui.gtk import graphics.ui.gtk.glade getbutton :: string -> readert gladexml io button getbutton buttonname = gladexml <- inquire homecoming . lift $ xmlgetwidget gladexml casttobutton buttonname

to run readert gladexml io action:

-- well, should utilize `runreadert` directly, @ to the lowest degree -- type signature here instructive. rungladexmlreader :: readert gladexml io -> gladexml -> io rungladexmlreader = runreadert

try reading docs on control.monad.trans.reader, , monad transformer tutorials.

let me seek again. i'm doing combining 2 ideas can tackle separately, set together:

the reader monad monad transformers

you might start reading these seek understand reader monad:

inside world (ode functor , monad); focus on section reader ("the world of future values") reader monad purpose help reader monad

basically, reader monad constructs values depend on missing, implicit "environment" value. within reader monad there action called ask :: reader r r result environment value.

so thought everywhere have gladexml -> something, can rewrite function monadic action of type reader gladexml something. example, simplification of illustration above (no monad transformer):

getbutton :: string -> reader gladexml (io button) getbutton buttonname = -- variable gladexml gets value of "implicit" gladexml value gladexml <- inquire -- utilize value argument xmlgetwidget function. homecoming $ xmlgetwidget gladexml casttobutton buttonname

the way utilize reader runreader :: reader r -> r -> a function. schematically:

{- note: none of guaranteed compile... -} illustration :: io button illustration = _ <- initgui -- setup xml <- loadgladefile "tutorial.glade" runreader (getbutton "button1") xml

however, since you're using both reader , io in here, want create combined monad has "powers" of both. that's monad transformers add together picture. readert gladexml io a is, conceptually, io action has access "implicit" gladexml value:

getbutton :: string -> readert gladexml io button getbutton buttonname = gladexml <- inquire -- there 1 catch: utilize io action, have prefix -- `lift` function... button <- lift $ xmlgetwidget gladexml casttobutton buttonname homecoming button -- i've refactored *not* take list of actions. onbuttonclick :: string -> readert gladexml io -> readert gladexml io () onbuttonclick gladexml buttonname action = abutton <- getbutton buttonname xml <- inquire _ <- lift $ onclicked abutton (runreadert action xml) homecoming () -- piece of code illustrates payoff of refactoring. -- note how there no variable beingness passed around xml. -- because i'm making "big" readert action out of little ones, , -- implicitly same `gladexml` value threaded through them. makebutton1 :: readert gladexml io button makebutton1 = button1 <- getbutton "button1" onbuttonclick "button1" $ lift $ putstrln "hello, world" homecoming button1 -- `main` action fetches `gladexml` value , hands off -- actual main logic, `readert` expects `gladexml` main :: io () main = xml <- ... runreadert actualmain xml actualmain :: readert gladexml io () actualmain = ...

haskell gtk glade

No comments:

Post a Comment