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

Grzegorz Milka grzegorzmilka at gmail.com
Sat Oct 17 06:09:24 UTC 2015


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




More information about the Beginners mailing list