piggyback
piggyback

Reputation: 9254

Use of monad >>= when variable is in the middle of a function in haskell

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?

Upvotes: 1

Views: 190

Answers (3)

Cat Plus Plus
Cat Plus Plus

Reputation: 129764

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.

Upvotes: 2

piggyback
piggyback

Reputation: 9254

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

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

Upvotes: 2

Adam Gordon Bell
Adam Gordon Bell

Reputation: 3093

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.

Upvotes: 1

Related Questions