3

I'm having trouble mixing up pure and monadic functions inside of do notation. I've got the feeling I am missing something obvious.

For example, say I got these functions

fa :: a -> IO b
fb :: b -> c
fc :: c -> IO d

z :: a -> IO c
z a = do x <- fa a
         y <- fb x
         z <- fc y
         return z

This doesn't work because of the

y <- fb x

line in z, but what is an elegant way of combining the pure fb function, with the monadic fa and fc functions?

Richard Deurwaarder
  • 2,023
  • 1
  • 26
  • 40
  • What's wrong with `let y = fb x`? – 9000 Dec 02 '15 at 18:04
  • Parens around a single variable are always superfluous, in `return (z)` as well as they would be in `fa a`. It is generally considered good style in Haskell to only use parentheses when they are necessary (unless of course [you're an MIT sophomore](http://www.willamette.edu/~fruehr/haskell/evolution.html))! – leftaroundabout Dec 02 '15 at 18:23
  • @leftaroundabout right you are! – Richard Deurwaarder Dec 02 '15 at 18:52

3 Answers3

7

Probably the smallest change you can make and have it still work is this:

z a = do x <- fa a
         let y = fb x
         z <- fc y
         return z

There are a number of things you can do in this specific case that may not work in the more general case. You can "inline" the call to fb; eliminate the bind/return pair; and use monadic composition instead of do-notation. Putting all three of these into practice would yield

z = fa >=> fc . fb

although you can pick just the transformations that seem reasonable/readable/aesthetically pleasing for your specific case.

Daniel Wagner
  • 145,880
  • 9
  • 220
  • 380
3

I'd write this particular example thus:

z a = do x <- fa a
         fc $ fb x

or

z a = fa a >>= fc . fb
leftaroundabout
  • 117,950
  • 5
  • 174
  • 319
1

Use let for non-monadic bindings:

z :: a -> IO c
z a = do x <- fa a
         let y = fb x
         z <- fc y
         return (z)
chi
  • 111,837
  • 3
  • 133
  • 218