[Haskell-beginners] State Monad: how to use other Stateful computation on sub-state inside

martin martin.drautzburg at web.de
Sat Oct 17 08:01:00 UTC 2015


This is quite insightful. Now the problem presents itself as follows:

In fact I orginally started with plain itmAdd (the one you called itmAdd'') which has no business with State or System.
It is just Item->ItemDb -> ItemDb.

However, I wanted to use do-notation and made it monadic leading to item' :: Item->State ItemDb ()

But then it becomes difficult to use it inside State System. Currently I am using

subState :: (s1 -> s2) -> State s2 a -> State s1 s2
subState accessor f   = do
    s <- get
    return $ execState f $ accessor s

to make the necessary transformation. I have the feeling that this way of stacking things is a bit inside-out. And as
you say, it only hides the ugliness. I will try to stack things bottom up.




Am 10/17/2015 um 08:09 AM schrieb Grzegorz Milka:
> Hi Martin,
> 
> I will present a few possibilities so that you can choose one that's
> available to you.
> 
> Let's first think about what the code is doing. It is adding an item to
> the ItemDB. However you are operating on the granulity of a System so
> you want a function of type:itmAdd :: Item -> System -> System. If we
> had it then we could write:
> 
> sysAddItem lbl vol cap pos t = do
>   sys <- get
>   id  <- sysNextId :: State SystemId
>   modify $ itmAdd (Itm id lbl vol cap pos t)
>   return id
> 
> That looks nicer. I'm guessing you don't have itmAdd at hand. One way
> would be to write it ourselves using itmAdd':
> 
> itmAdd :: Item -> System -> System
> itmAdd item s = s{sysItems=execState (itmAdd' item) (sysItems s)}
> 
> So this solution only hides the ugliness. The reason why it appears is
> because itmAdd' has a too specific type - an unnecessary State. What it
> essentially does is it adds an Item to ItemDB, so: itmAdd'' :: Item ->
> ItemDB -> ItemDB, then the function would look better. I myself would
> first write itmAdd'' (instead of itmAdd') and then if I really needed
> itmAdd' in multiple places I would write
> 
> itmAdd item s = s{sysItems=itmAdd'' item $ sysItems s}
> itmAdd' item = modify $ itmAdd'' item
> 
> The code here still may look nicer, but only slightly. My message here
> is that it is beneficial to think first about what are the most general
> types that you need and then perhaps splitting them into a combination
> of other general types. Here the root cause of the ugliness is that you
> too an unnecessarily specific type of itemAdd'.
> 
> Best regards,
> Grzegorz
> 
> On 16.10.2015 22:28, martin wrote:
>> Hello all,
>>
>> I found myself writing this piece of code:
>>
>> -- | Create and add a new 'Item' to the system
>> sysAddItem :: ItmLabel -> ItmVolume -> ItmCapacity -> Position -> Instant
>>            -> State System ItmId
>>
>> sysAddItem lbl vol cap pos t = do
>>     sys  <- get
>>     id   <- sysNextId :: State System Id
>>
>>     itms' <- return $ execState  (itmAdd' (Itm id lbl vol cap pos t)) (sysItems sys) --**
>>
>>     modify (\sys -> sys{sysItems=itms'})
>>     return id
>>
>>
>> In the lonely line ** in the middle I use
>>
>> 	itmAdd' :: Item -> State ItemDb (),
>>
>> where the ItemDb is part of the  'System' and can be extracted via sysItems. I believe this code is correct, but I don't
>> like it.
>>
>> The expression to the right of <- must have the type
>>
>> 	State System ItemDb
>>
>> But ItemAdd' has the type
>>
>> 	Item -> State ItemDb ()
>>
>> So I need to transform
>>
>> 	(Item -> State ItemDb ()) to (State System ItemDb).
>>
>> There is no question that I have to pass the Item, but the transformation of the States is quite noisy. Is there a
>> better way to make this transformation, given a function System->ItemDb (i.e. sysItems)?
>> _______________________________________________
>> Beginners mailing list
>> Beginners at haskell.org
>> http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners
> 
> 
> _______________________________________________
> Beginners mailing list
> Beginners at haskell.org
> http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners
> 



More information about the Beginners mailing list