<div dir="ltr"><br><div class="gmail_extra"><br><div class="gmail_quote">On Sat, May 9, 2015 at 12:54 AM, Alexander V Vershilov <span dir="ltr"><<a href="mailto:alexander.vershilov@gmail.com" target="_blank">alexander.vershilov@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Hi, Gleb.<br>
<br>
Assuming that you already in IO, and don't want to use lift or liftIO<br>
to lift actions into another stack level, you can choose one of the<br>
following:<br>
<br>
1. Create a module with lifted operations for all operations in the<br>
framework. Then by the cost of some boilerplate code you'll have<br>
a framework that could be used in any MonadBaseControl.<br></blockquote><div><br></div><div>I'd go this way for bindings library itself, but i'm wonder why bindings to other toolkits use plain IO.<br><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
2. Another way is to introduce concurrent primitives that will allow<br>
you to 'log' events. Here is an incomplete sketch:<br>
<br>
data ConfigUI = CUI { setText :: Text -> IO (),  setAnotherText ::<br>
Text -> IO () }<br>
<br>
defCUI = ...<br>
<br>
newtype LogRef a = LV (IORef (Endo a))<br>
<br>
newLog  :: IO (LogRef a)<br>
newLog = LV <$> newIORef id<br>
<br>
writeLog :: LogRef a -> (a -> a) -> IO ()<br>
writeLog (LV r) f = modifyIORef r (\x -> x <> Endo f)<br>
<br>
applyLog :: LogRef a -> a -> IO a<br>
applyLog (LV r) f = ($) <$> fmap appEndo (readIORef r)  <*>  pure f<br>
<br>
withLog ::  a -> (LogRef a -> IO b) -> IO (a,b)<br>
withLog f v = newLog >>= \l -> f l >>= liftM2 (,) (applyLog lg v)<br>
<br>
configureConfigUI = do<br>
     (cui, a) <- withLog defCUI $ \lg -> do<br>
                        ....<br>
                        writeLog (\x -> x{setText = entrySet e})<br></blockquote><div><br></div><div>This is, basically, a reimplementation of Writer monad functionality using mutable variables in IO. I've also come up with this, but was hoping to somehow reuse existing Writer monad.<br><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
There is a big window for solutions that are using mutable references<br>
to log events in IO monad. Each with it's own pros and cons.<br>
<br>
Hope it helps<br>
<br>
--<br>
Alexander<br>
<div><div class="h5"><br>
On 8 May 2015 at 14:20, Gleb Popov <<a href="mailto:6yearold@gmail.com">6yearold@gmail.com</a>> wrote:<br>
> Hello haskell-cafe@<br>
><br>
> I'm writing a GUI app in Haskell and bindings to the widget toolkit i'm<br>
> using in parallel. These bindings are very simple and all its functions have<br>
> return type (IO something).<br>
><br>
> So far so good, i wrote the following code to create an config window:<br>
><br>
> createConfigUI root = do<br>
>     box <- Box.add root<br>
><br>
>     -- first field<br>
>     addToPackEnd box =<< do<br>
>         f <- Fr.add box<br>
>         setPartText f Nothing "E-mail"<br>
>         setPartContent f Nothing =<< do<br>
>             box <- Box.add box<br>
><br>
>             addToPackEnd box =<< do<br>
>                 e <- Ent.add box<br>
>                 Ent.singleLineSet e True<br>
>                 -- Here<br>
>                 onEvent "changed,user" e $ do<br>
>                      reactOnUserInput e<br>
>                 objectShow e<br>
>                 return e<br>
><br>
>             objectShow box<br>
>             return box<br>
><br>
>         objectShow f<br>
>         return f<br>
><br>
>     -- next field<br>
>     addToPackEnd box =<< do<br>
>         ...<br>
><br>
> Initially, i was quite satisfied with flipped bind use for creating UI<br>
> elements and arranging them. Nested do scopes allow copypasting code without<br>
> renaming variables and also provide some visual representation on widget<br>
> hierarchy.<br>
><br>
> But at some point i need to return some stuff from some inner do block into<br>
> outmost. For example, at the line with comment "Here" i defined<br>
><br>
> let setText t = entrySet e t<br>
><br>
> and wanted to return it from whole createConfigUI action. Moreover,<br>
> createConfigUI have much more fields, for each of them i want to do the<br>
> same.<br>
><br>
> My initial thought was to wrap everything with runWriter and just call<br>
><br>
> tell setText<br>
><br>
> wherever i want to gather all setter functions into a list, but i can't do<br>
> this because i would need to put liftIO before every IO action all over the<br>
> place.<br>
><br>
> If only there was i way to turn an (IO a) into (MonadIO m => m a), it would<br>
> be easy.<br>
><br>
> Another solution is to make my bindings return (MonadIO m => m a). This<br>
> would be equal effort of plugging liftIO's everywhere, but at least it would<br>
> be hidden from user of bindings. I'd gone this way, but looked at gtk<br>
> bindings first and found that (IO a) is used there.<br>
><br>
> So, my questions are:<br>
><br>
> 1. What would you recommend in my situation? Is it possible yield values<br>
> from inner do blocks into outer without much hassle?<br>
> 2. If there is nothing wrong with switching bindings from (IO a) to MonadIO<br>
> typeclass, why not to do this for gtk, wxWidgets and nearly every FFI<br>
> binding?<br>
><br>
> Thanks in advance.<br>
><br>
</div></div>> _______________________________________________<br>
> Haskell-Cafe mailing list<br>
> <a href="mailto:Haskell-Cafe@haskell.org">Haskell-Cafe@haskell.org</a><br>
> <a href="http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe" target="_blank">http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe</a><br>
><br>
<span class="HOEnZb"><font color="#888888"><br>
<br>
<br>
--<br>
Alexander<br>
</font></span></blockquote></div><br></div></div>