Send Beginners mailing list submissions to
[email protected]
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
[email protected]
You can reach the person managing the list at
[email protected]
When replying, please edit your Subject line so it is more specific
than "Re: Contents of Beginners digest..."
Today's Topics:
1. State Monad: how to use other Stateful computation on
sub-state inside (martin)
2. Re: State Monad: how to use other Stateful computation on
sub-state inside (Grzegorz Milka)
3. Re: State Monad: how to use other Stateful computation on
sub-state inside (Karl Voelker)
4. Re: State Monad: how to use other Stateful computation on
sub-state inside (martin)
----------------------------------------------------------------------
Message: 1
Date: Fri, 16 Oct 2015 22:28:47 +0200
From: martin <[email protected]>
To: [email protected]
Subject: [Haskell-beginners] State Monad: how to use other Stateful
computation on sub-state inside
Message-ID: <[email protected]>
Content-Type: text/plain; charset=utf-8
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)?
------------------------------
Message: 2
Date: Sat, 17 Oct 2015 08:09:24 +0200
From: Grzegorz Milka <[email protected]>
To: The Haskell-Beginners Mailing List - Discussion of primarily
beginner-level topics related to Haskell <[email protected]>
Subject: Re: [Haskell-beginners] State Monad: how to use other
Stateful computation on sub-state inside
Message-ID: <[email protected]>
Content-Type: text/plain; charset=windows-1252
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
> [email protected]
> http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners
------------------------------
Message: 3
Date: Sat, 17 Oct 2015 00:40:13 -0700
From: Karl Voelker <[email protected]>
To: The Haskell-Beginners Mailing List - Discussion of primarily
beginner-level topics related to Haskell <[email protected]>
Subject: Re: [Haskell-beginners] State Monad: how to use other
Stateful computation on sub-state inside
Message-ID: <[email protected]>
Content-Type: text/plain; charset=utf-8
> On Oct 16, 2015, at 1:28 PM, martin <[email protected]> wrote:
>
> The expression to the right of <- must have the type
>
> State System ItemDb
>
> But ItemAdd' has the type
>
> Item -> State ItemDb ()
You have an insight here which is quite general. If you have a monad State s,
where s has a subcomponent of type t, you should be able to transform any
action State t a into an ?equivalent? action State s a, where instead of acting
on the whole state, you act on the subcomponent.
What would we need in order to do that transformation in a general way? A
function to get the subcomponent out of the whole, and a function to put the
new value of the subcomponent back into the whole. In other words, we?d need
functions of types s -> t and t -> s -> s.
Putting all of that together, we can imagine a transformation like this:
f :: (s -> t) -> (t -> s -> s) -> State t a -> State s a
I know of some libraries which provide a function with roughly that same type.
The difference is that the first two parameters, the ?getter? and ?setter?, are
combined into one parameter, and this combined thing is called a ?lens?. Lenses
are useful in all kinds of situations, and this just happens to be one of them.
Of course, if you don?t already have a lens, any lens library will give you a
way to build one out of the getter and setter functions.
Anyway, the two library functions which provide this transformation are called
focus (in the data-lens-fd package, which is used with the lens type defined in
the data-lens package) [1] and zoom (in the lens package) [2]. The lens package
is more powerful, but also a good deal more confusing, so I would start with
data-lens and data-lens-fd if you want a gentle introduction to lenses.
-Karl
1:
http://hackage.haskell.org/package/data-lens-fd-2.0.5/docs/Data-Lens.html#v:focus
2:
http://hackage.haskell.org/package/lens-4.13/docs/Control-Lens-Zoom.html#v:zoom
------------------------------
Message: 4
Date: Sat, 17 Oct 2015 10:01:00 +0200
From: martin <[email protected]>
To: The Haskell-Beginners Mailing List - Discussion of primarily
beginner-level topics related to Haskell <[email protected]>
Subject: Re: [Haskell-beginners] State Monad: how to use other
Stateful computation on sub-state inside
Message-ID: <[email protected]>
Content-Type: text/plain; charset=windows-1252
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
>> [email protected]
>> http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners
>
>
> _______________________________________________
> Beginners mailing list
> [email protected]
> http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners
>
------------------------------
Subject: Digest Footer
_______________________________________________
Beginners mailing list
[email protected]
http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners
------------------------------
End of Beginners Digest, Vol 88, Issue 13
*****************************************