Reputation: 9254
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
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
Reputation: 9254
I got it my self too but using lambda notation :)
showBalls = getInt >>= (\a -> return . take a $ repeat 9 )
Upvotes: 2
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