Article View: comp.lang.functional
Article #947for monad lovers only
From: Luc Duponcheel
Date: Mon, 14 Dec 1992 15:00
Date: Mon, 14 Dec 1992 15:00
201 lines
5473 bytes
5473 bytes
In his article jones-mark@cs.yale.edu (Mark Jones) writes something like :
>Now we're ready for the generalization. The type constructor
>State b is a monad M so that we could actually define a more general
>version of row that works for any monad M using:
>
>
> mapl :: (a -> M b) -> ([a] -> M [b])
> mapl f [] = unitM []
> mapl f (x:xs) = f x `bindM` \y ->
> mapl f xs `bindM` \ys ->
> unitM (y:ys)
>
Now that the function row has been generalised
we might as well go one step further by generalising mapl.
First I would like to introduce (for notational convenience only)
the function
appM :: (a -> M b) -> M a -> M b
appM = flip bindM
Using this function and writing L a instead of [a] one has
mapl :: (a -> M b) -> L a -> M (L b)
mapl f [] = unitM []
mapl f (x:xs) = appM (\y -> appM (unitM . (y:)) (mapl f xs)) (f x)
The generalisation involves the combination of monads.
If M and L are monads, then their composition (M . L) is also a monad
IFF there exists a function
joinL_M :: L (M (L a)) -> M (L a)
with the following properties
joinL_M . unitL = id
joinL_M . joinL = joinL_M . mapL joinL_M
joinL_M . mapL unitML = unitM
joinL_M . mapLML g = mapML g . joinL_M
joinL_M . mapL joinML = joinML . joinL_M
where
unitML = unitM . unitL
mapML = mapM . mapL
joinML = joinM . mapM joinL_M
or, equivalently, IFF there exists a function
swapL_M :: L (M a) -> M (L a)
with the following properties
swapL_M . unitL = mapM unitL
swapL_M . joinL = mapM joinL . swapL_M . mapL swapL_M
swapL_M . mapL unitM = unitM
swapL_M . mapL joinM = joinM . mapM swapL_M . swapL_M
swapL_M . mapLM f = mapML f . swapL_M
or, equivalently, IFF there exists a function
appM_L :: (L a -> M b) -> L (M a) -> M b
with similar properties
(the details will appear in a forthcoming paper)
the functions joinL_M, swapL_M and appM_L
can be defined in terms of each other as follows :
swapL_M = joinL_M . mapL (mapM unitL)
appM_L f = joinM . mapM f . swapL_M
joinL_M = appM_L (unitM . joinL)
888888888888888888888888888888888888888888888
88 Now we are ready for the generalisation 88
888888888888888888888888888888888888888888888
we can define a general purpose function
mapM_L :: (a -> M b) -> L a -> M (L b)
mapM_L f = joinL_M . mapL (mapM unitL . f)
In the case of lists the function appM_L looks as follows
appM_L f [] = f []
appM_L f [m] = appM (f . unitL) m
appM_L f (m:ms) = appM (\y -> appM_L (f . (y:)) ms) m
Let's proof that mapl and mapM_L are equal !
it is clear that
mapl f [] = unitM []
and
mapl f (x:xs) =
appM (\y -> appM (unitM . (y:)) (mapl f xs)) (f x)
mapM_L f [] = unitM []
and
mapM_L f (x:xs)
= joinL_M . mapL (mapM unitL . f) (x:xs)
= (appM_L (unitM . joinL) . mapL (mapM unitL . f)) (x:xs)
= appM_L (unitM . joinL) (mapL (mapM unitL . f) (x:xs))
= appM_L (unitM . joinL) (mapM unitL . f) x : (mapL (mapM unitL . f) xs)
= appM (\y -> appM_L (unitM . joinL . (y:)) (mapL (mapM unitL . f) xs) (mapM unitL . f) x
= appM (\y -> appM_L (unitM . joinL . (y:)) (mapL (mapM unitL . f) xs) (mapM unitL (f x))
= appM (\y -> appM_L (unitM . joinL . ((unitL y):)) (mapL (mapM unitL . f) xs)) (f x)
(the last equation uses : appM g . mapM f = appM (g . f))
thus mapl f [] = mapM_L f [] and we can now use INDUCTION
thus we have to prove that
appM (unitM . (y:)) ((appM_L (unitM . joinL) . mapL (mapM unitL . f)) xs)
is equal to
appM_L (unitM . joinL . ((unitL y):)) (mapL (mapM unitL . f) xs)
or equivalently
appM (unitM . (y:)) . appM_L (unitM . joinL) . mapLM unitL
is equal to
appM_L (unitM . joinL . ((unitL y):)) . mapLM unitL
NOW
appM (unitM . (y:)) . appM_L (unitM . joinL) . mapLM unitL
= appM (unitM . (y:)) . joinL_M . mapL (swapL_M . unitL)
= appM (unitM . (y:)) . joinL_M . mapL swapL_M . mapL unitL
= appM (unitM . (y:)) . mapM joinL . swapL_M . mapL swapL_M . mapL unitL
= appM (unitM . (y:) . joinL) . swapL_M . mapL (swapL_M . unitL)
= appM (unitM . joinL . ((unitL y):)) . swapL_M . mapLM unitL
and we are done!!
TO CONCLUDE :
If M and L are monads and if their combination M . L is again a monad,
then one can define a function
mapM_L :: (a -> M b) -> L a -> M (L b)
mapM_L f = joinL_M . mapL (mapM unitL . f)
of which mapl (and therefore also row) is a special case.
BTW:
I'd like to thank Mark Jones for all the
work he is doing for making the use of monads
in gofer notationally more convenient.
PS:
it would be nice to be able to write something like
( Monad M, Monad L) => Monad (M . L) where
prod :: (L . M . L) a -> (M . L) a
map = map . map
unit = unit . unit
join = join . map prod
Luc Duponcheel. (ldup@alcbel.be)
\_ \_\_\_ \_ \_ \_\_\_
\_ \_ \_ \_ \_ \_ \_
\_ \_ \_ \_ \_ \_\_\_
\_ \_ \_ \_ \_ \_
\_\_\_\_ \_\_\_ \_\_\_\_ \_
Technical Details
Message-ID:
<1927@alcbel.be>Path:
arc1-ca.pugleaf.net!sparky!uunet!mcsun!ub4b!alcbel!ta7s49.alcbel.beShow Full Headers
Complete Article Headers
Path: arc1-ca.pugleaf.net!sparky!uunet!mcsun!ub4b!alcbel!ta7s49.alcbel.be From: ldup@ta7s49.alcbel.be (Luc Duponcheel) Newsgroups: comp.lang.functional Subject: for monad lovers only Message-ID: <1927@alcbel.be> Date: 14 Dec 92 15:00:47 GMT Sender: ldup@alcbel.be Organization: Alcatel Bell Telephone, Antwerpen, Belgium Lines: 207