home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #30 / NN_1992_30.iso / spool / comp / lang / function / 1469 < prev    next >
Encoding:
Text File  |  1992-12-16  |  4.6 KB  |  131 lines

  1. Newsgroups: comp.lang.functional
  2. Path: sparky!uunet!gumby!yale!cs.yale.edu!news
  3. From: jones-mark@CS.YALE.EDU (Mark P. Jones)
  4. Subject: Re: for monad lovers only
  5. Message-ID: <1992Dec16.153318.506@cs.yale.edu>
  6. Keywords: monads Gofer overloading
  7. Sender: news@cs.yale.edu (Usenet News)
  8. Nntp-Posting-Host: chickadee.systemsz.cs.yale.edu
  9. Organization: Yale University, Department of Computer Science, New Haven, CT
  10. References: <1927@alcbel.be>
  11. Date: Wed, 16 Dec 1992 15:33:18 GMT
  12. Lines: 117
  13.  
  14. In article <1927@alcbel.be> ldup@ta7s49.alcbel.be (Luc Duponcheel) writes:
  15. |  In his article jones-mark@cs.yale.edu (Mark Jones) writes something like :
  16. |  
  17. |  >Now we're ready for the generalization.  The type constructor
  18. |  >State b is a monad M so that we could actually define a more general
  19. |  >version of row that works for any monad M using:
  20. |  >
  21. |  >    mapl  :: (a -> M b) -> ([a] -> M [b])
  22. |  >    mapl f []     = unitM []
  23. |  >    mapl f (x:xs) = f x         `bindM` \y ->
  24. |  >                    mapl f xs   `bindM` \ys ->
  25. |  >                    unitM (y:ys)
  26. |  >
  27. |  
  28. |  Now that the function row has been generalised
  29. |  we might as well go one step further by generalising mapl.
  30.  
  31. Thanks Luc!  I've worked through your message and I thought you (and
  32. others) might be interested to see how it looks in the notation I'm
  33. using.
  34.  
  35. First of all, Luc gives three equivalent conditions for being able
  36. to compose two monads to form another.  More precisely, Luc gives three
  37. operators and states that, if you can find a definition for one of these
  38. satisfying certain laws, then you can compose the monads (and give
  39. definitions for the other two operators).
  40.  
  41. With this in mind, we introduce a two parameter class of composable
  42. monads:
  43.  
  44.     class (Monad m, Monad l) => Composable m l where
  45.         prod  :: l (m (l a)) -> m (l a)
  46.         swap  :: l (m a) -> m (l a)
  47.         app   :: (l a -> m b) -> l (m a) -> m b
  48.  
  49.         prod   = app (return . join)
  50.         swap   = prod . map (map return)
  51.         app f  = join . map f . swap
  52.  
  53. In order to specify an instance of this class, we only need to specify
  54. a value for one of the three functions prod, swap and app.  The default
  55. definitions at the end of the class declaration can be used to generate
  56. the other two.  (Of course, it would be a mistake to omit definitions
  57. for all three since the definitions are obviously circular).  For
  58. example, we can express the fact that any monad is composable with the
  59. list monad by writing:
  60.  
  61.     instance Composable m [ ] where
  62.         swap []     = [ [] ]
  63.         swap (x:xs) = [ y:ys | y<-x, ys<-swap xs ]
  64.  
  65. (In the context of a type expression, the notation [ ] represents the
  66. list constructor.  I didn't want to make another reserved word, although
  67. things might be prettier to if we wrote it as List.)
  68.  
  69. Now Luc's generalization of my generalization can be defined by:
  70.  
  71.     mmap f = swap . map f
  72.  
  73. This is equivalent to Luc's original definition (from subsequent mail,
  74. I think both Luc and I discovered this simpler form after he had sent
  75. his message).  You'll notice that I've left of the type of mmap; this
  76. is so that I can show you that type inference really does give the
  77. type we want:
  78.  
  79.     ? :t mmap
  80.     mmap :: Composable b d => (a -> b c) -> d a -> b (d c)
  81.     ?
  82.  
  83. Ok, so we might have used names like l and m instead of b and d,
  84. but other than that, this is the type that you would expect.
  85.  
  86. |  it would be nice to be able to write something like
  87. |  
  88. |      ( Monad M, Monad L) => Monad (M . L) where
  89. |          prod :: (L . M . L) a -> (M . L) a
  90. |  
  91. |          map = map . map
  92. |          unit = unit . unit
  93. |          join = join . map prod
  94.  
  95. Here's the closest that I can get to this at the moment.  I'm not
  96. sure how useful this would be for practical programming though.
  97. Perhaps somebody else can comment on that.
  98.  
  99. First, the definition of the composition of two type constructors:
  100.  
  101.     type Comp f g a = f (g a) in mapComp, returnComp, joinComp
  102.  
  103. This uses a restricted type synonym; the expansion of Comp f g a
  104. is only permitted in the binding groups of the functions mapComp,
  105. returnComp and joinComp to be defined below.
  106.  
  107. Let's start with the fact that Comp f g is a functor:
  108.  
  109.     mapComp :: (Functor f,Functor g) => (a->b) -> (Comp f g a->Comp f g b)
  110.     mapComp  = map . map
  111.  
  112.     instance (Functor f, Functor g) => Functor (Comp f g) where
  113.         map = mapComp
  114.  
  115. Now we can move on to describe the monad structure of the composition:
  116.  
  117.     returnComp :: (Monad f, Monad g) => a -> Comp f g a
  118.     returnComp  = return . return
  119.  
  120.     joinComp   :: (Composable f g) => Comp f g (Comp f g a) -> Comp f g a
  121.     joinComp    = join . map prod
  122.  
  123.     instance Composable f g => Monad (Comp f g) where
  124.         return = returnComp
  125.         join   = joinComp
  126.  
  127. How does that look?
  128.  
  129. All the best,
  130. Mark
  131.