[Haskell-cafe] Fwd: Monad Transformers stack with variable depth

Ivan Perez ivanperezdominguez at gmail.com
Wed Mar 7 11:36:25 UTC 2018


Hi Leonidas

This is an interesting example. If I understand you correctly, what you
want to do is to focus on one particular item, apply a (State) monadic
computation that modifies it, replace that in the main list, as part of a
larger monadic computation (also in a State monad / StateT transformer).

The first part, focusing on a sub-element, is fine. You could have an
operation on a State monad that allows you to focus on a substate. But the
problem is merging the result back into the main state: that would not
happen automatically.

(Note for other readers: reminds me of lenses. Maybe StateT and Lens can be
combined?)

It seems to me that, in this case, what you are already doing would be
roughly the way to do it (if you want to use State also to modify the inner
items).

Example of state transformers:

Imagine that you have an additional, distinguished Item, that you need to
keep apart (apart is the keyword, not the fact that it's only one).

Then the monad you would be handling would be like:

State (ItemManager, Item)

No matter how many Items you have in the ItemManager (may be zero), you
always have a distinguished Item separated.

But that means that, to manipulate this, you'd have to extract the
ItemManager, modify it, put it back in the tuple, etc. So, you can also do:

StateT ItemManager (State Item)

Which means that you can modify ItemManager and Item independently, and
manipulate both with:

op :: StateT ItemManager (State Item) ()
op = do
  modify f           -- computation that affects item manager
  lift (modify g)   -- computation that affects single item
  ...

You would then define your operations to be more flexible:

increaseCounterInItems :: StateT ItemManager m ()

So, you could also do:

op :: StateT ItemManager (State Item) ()
op = do
  increaseCounterIntItems     -- adds one to every Item in ItemManager
  lift increaseCounter          -- adds one to the single Item
  ...

Hope that helps

Best wishes

Ivan


On 6 March 2018 at 17:46, leonidasbo . <leonidasbo at gmail.com> wrote:

> Hello,
>
> I am a beginner with Haskell and the last few days I am troubled on how to
> form a stack of Monad Transformers.
> The following example demonstrates the use of multiple State monads
> without the use of Monad Transformers:
>
> data Item = Item { rCounter :: Int }
>
> increaseCounter :: State Item ()
> increaseCounter = do
>   val <- gets rCounter
>   modify (\i -> i { rCounter = val + 1 })
>
> data ItemManager = ItemManager { rItems :: [Item] }
>
> addItem :: Item -> State ItemManager ()
> addItem item = do
>   items <- gets rItems
>   modify (\mgr -> mgr { rItems = items ++ [item] })
>
> increaseCounterInItems :: State ItemManager ()
> increaseCounterInItems = do
>   items <- gets rItems
>   let items' = map *(execState increaseCounter)* items
>   modify (\mgr -> mgr { rItems = items' })
>
> main :: IO ()
> main = $ do
>   let itemMgrState = do
>         addItem $ Item 0
>         addItem $ Item 10
>         increaseCounterInItems
>
>   let itemMgr = execState itemMgrState $ ItemManager []
>
>   let items = rItems itemMgr
>   putStrLn rCounter (items !! 0) -- prints 1
>   putStrLn rCounter (items !! 1) -- prints 11
>
> In the above implementation calls *execState, *inside functions of
> ItemManager, for updating Items.
> I have read about MonadTransformers and that they give you the ability to
> use monads inside the context of another monad.
> So I would like to use StateT in signatures of ItemManager's functions and
> avoid calling *execState, *something like this:
>
> increaseCounterInltems :: StateT ItemManager (State Item) ()
>
> But I cannot find a way to implement the above function. The root cause of
> the difficulty seems to be that ItemManager contains multiple Items.
> The Monad Transformer stack contains a single State Item. So it seems to
> me that I am following the wrong approach.
>
> How could I use Monad Transformers in order to avoid calling *execState*
> for modifying Items in ItemManager?
>
> Thanks in advance,
> Leonidas
>
>
> <https://www.avast.com/sig-email?utm_medium=email&utm_source=link&utm_campaign=sig-email&utm_content=webmail&utm_term=icon> Virus-free.
> www.avast.com
> <https://www.avast.com/sig-email?utm_medium=email&utm_source=link&utm_campaign=sig-email&utm_content=webmail&utm_term=link>
> <#m_8570978510949558714_m_-5826819471182298913_DAB4FAD8-2DD7-40BB-A1B8-4E2AA1F9FDF2>
>
>
> _______________________________________________
> Haskell-Cafe mailing list
> To (un)subscribe, modify options or view archives go to:
> http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
> Only members subscribed via the mailman list are allowed to post.
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.haskell.org/pipermail/haskell-cafe/attachments/20180307/52971188/attachment.html>


More information about the Haskell-Cafe mailing list