1

Hello there here is my issue. This is my running code, which is fine:

showBalls = do howMany <- getInt return . take HowMany $ repeat 9 

where my getInt does several checks in order to retrieve user input Int. However, my question is, is there a way to rewrite this part of code with the use of monads?

My aim is to use >>= and have a final one-line functions such as:

showBalls = fmap (take <$> (repeat 9)) getLine 

however it doesnt work (as expected). Any suggestion?

2
  • 1
    One line doesn't mean better. Also, that part of the code already uses monads. Commented Jan 9, 2013 at 18:03
  • Yep yep, I perfectly understand. It is not about what's better, it is about understanding the language I think :) Commented Jan 9, 2013 at 18:05

3 Answers 3

2

You can use flip to reverse the arguments of take, which makes it possible to apply repeat 9 to it and get function:

> :t flip take (repeat 9) flip take (repeat 9) :: Num a => Int -> [a] 

To use >>= with getInt we need Int -> IO a function:

> :t (getInt >>=) (getInt >>=) :: (Int -> IO b) -> IO b 

To get that, compose with return (it's m [a] because it will work for every monad, but is also restricted to lists; from the above type, m becomes IO and b becomes [a]):

> :t return . flip take (repeat 9) return . flip take (repeat 9) :: (Monad m, Num a) => Int -> m [a] 

The final expression is:

> :t getInt >>= return . flip take (repeat 9) getInt >>= return . flip take (repeat 9) :: Num a => IO [a] 

But, as I mentioned, I'm not really convinced it's strictly better than the original. As a more useful bit of knowledge, playing around with expressions and their types in GHCi is a good way of inventing transformations like that.

Sign up to request clarification or add additional context in comments.

3 Comments

Or, since x >>= return . f is fmap f x or f <$> x, this can be further simplified to flip take (repeat 9) <$> getInt
you meant fmap take (repeat 9) <$> getInt?
@haskellguy: no, flip is correct. The <$> is already doing the fmap.
2

I got it my self too but using lambda notation :)

showBalls = getInt >>= (\a -> return . take a $ repeat 9 ) 

1 Comment

This version with the lambda is actually exactly what do notation dessugars into. haskell.org/haskellwiki/Monad#Special_notation
1

I believe this should work:

showBalls = (liftM . flip take $ repeat 9) getInt 

There is probably point free way to do it as well, but I couldn't figure it out.

4 Comments

It doesn't type-check, it should be $ instead of .
There's no way this composition makes sense: liftM's first argument is a function, not a list.
Maybe I wrote it in a confusing way. liftM does get a function : liftM . flip take
Welp, nevermind, I tested something else. Damn you, operator precedence.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.