Send Beginners mailing list submissions to beginners@haskell.org To subscribe or unsubscribe via the World Wide Web, visit http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners or, via email, send a message with subject or body 'help' to beginners-requ...@haskell.org
You can reach the person managing the list at beginners-ow...@haskell.org When replying, please edit your Subject line so it is more specific than "Re: Contents of Beginners digest..." Today's Topics: 1. State in IO monad (Dmitriy Matrosov) 2. Re: State in IO monad (c...@coot.me) ---------------------------------------------------------------------- Message: 1 Date: Sat, 14 Nov 2020 16:53:35 +0300 From: Dmitriy Matrosov <sgf....@gmail.com> To: beginners@haskell.org Subject: [Haskell-beginners] State in IO monad Message-ID: <72b8181f-1e5b-f4a4-c336-8157b26aa...@gmail.com> Content-Type: text/plain; charset=utf-8; format=flowed Hi. I want to use [telnet library][1] to run some commands on cisco switches and then parse output. Thus, first i need to login (enter username and password, etc) and then run commands and collect output. As far as i understand that library API, all of output parsing should be done in EventHandler of type TelnetPtr -> Event -> IO () But, these (mine) operations require some state (to track where am i now (entered username, entered password, etc) and to collect output). But the monad of this event handler is IO, so i can't see any simple way of adding state to it apart from ['unsafePerfromIO' trick][2], like telnetRef :: IORef TelnetRef {-# NOINLINE telnetRef #-} telnetRef = unsafePerformIO $ newIORef (TelnetRef undefined Unauth M.empty) ('undefined' is 'Telnet' pointer, which is returned by 'telnetInit' and will be initialized later..) Is there a better a way to do this? Thanks. [1]: https://hackage.haskell.org/package/libtelnet [2]: https://wiki.haskell.org/Top_level_mutable_state ------------------------------ Message: 2 Date: Sat, 14 Nov 2020 14:36:06 +0000 From: c...@coot.me To: The Haskell-Beginners Mailing List - Discussion of primarily beginner-level topics related to Haskell <beginners@haskell.org> Subject: Re: [Haskell-beginners] State in IO monad Message-ID: <RHOjSMVDRyRLCT60sErhau5ddCy_OUVCVgCbP3HS2USME5KeslEWfsjcs6D8GFU6ERQrxsKrmHNvlWY-OhQXMaXGaaP5c5UyLbgHsbr7SQY=@coot.me> Content-Type: text/plain; charset="utf-8" Hi, First you should ask yourself if you need concurrent access to that state. If not then you can thread this state as argument, e.g. ``` data State = State someAction :: State -> IO a someOtherAction :: State -> IO b ``` This functions compose perfectly well, if you need to update the state then each action should also return it: ``` someAction :: State -> IO (State, a) someOtherAction :: State -> IO (State, b) ``` You still can compose those. This is `StateT` monad transformer in disguise (from `transformers` / `stm` package combo), but I personally prefer to pass arguments explicitly and only use `StateT` or `RederT` monad if they bring more clarity. If you need concurrent access from different threads, then I'd use `MVar` or `stm` for holding a mutable variable, rather than `IORef` (which are useful if the code needs to be as fast as possible, but they present less guarantees). If you go with mutable cell to hold the state, then there's no need to create it using `unsafePerformIO`, you can directly create it in `main :: IO ()` and pass it around as an argument. `unsafePerformIO` is really rarely needed and most of the time there are well established patterns to avoid using it. Best regards, Marcin Szamotulski ‐‐‐‐‐‐‐ Original Message ‐‐‐‐‐‐‐ On Saturday, November 14th, 2020 at 14:53, Dmitriy Matrosov <sgf....@gmail.com> wrote: > Hi. > > I want to use [telnet library][1] to run some > > commands on cisco switches and then parse output. > > Thus, first i need to login (enter username and > > password, etc) and then run commands and collect > > output. As far as i understand that library API, > > all of output parsing should be done in > > EventHandler > > of type > > TelnetPtr -> Event -> IO () > > But, these (mine) operations require some state > > (to track where am i now (entered username, > > entered password, etc) and to collect output). But > > the monad of this event handler is IO, so i can't > > see any simple way of adding state to it apart > > from ['unsafePerfromIO' trick][2], like > > telnetRef :: IORef TelnetRef > > {-# NOINLINE telnetRef #-} > > telnetRef = unsafePerformIO $ newIORef (TelnetRef undefined Unauth M.empty) > > ('undefined' is 'Telnet' pointer, which is > > returned by 'telnetInit' and will be initialized > > later..) > > Is there a better a way to do this? > > Thanks. > > [1]: https://hackage.haskell.org/package/libtelnet > > [2]: https://wiki.haskell.org/Top_level_mutable_state > > Beginners mailing list > > Beginners@haskell.org > > http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 509 bytes Desc: OpenPGP digital signature URL: <http://mail.haskell.org/pipermail/beginners/attachments/20201114/e1e530af/attachment-0001.sig> ------------------------------ Subject: Digest Footer _______________________________________________ Beginners mailing list Beginners@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners ------------------------------ End of Beginners Digest, Vol 148, Issue 1 *****************************************