ceno980
ceno980

Reputation: 2011

Haskell: Understanding the bind and >> functions

I have the following Haskell expression:

a = getLine >>= putStrLn . filter isDigit >> a

I am having trouble understanding how the above expression works. I know the >>= function takes a monadic value and a function (that takes a normal value and returns a monadic value), and returns a monadic value.

I know that getLine and putStrLn have the following type declarations:

getLine :: IO String 
putStrLn :: String -> IO ()

So the following part of expression:

a = getLine >>= putStrLn . filter isDigit

Would return an IO (). However, the function >> takes a first monadic value and a second monadic value and returns the second monadic value.

Given the original expression, the first argument passed to >> would be of type IO String. The second argument is a.

My question is, what is the type of a, and how does the above expression work to continually take user input and print only the numeric part of the input back to the screen? Any insights are appreciated.

Upvotes: 2

Views: 501

Answers (2)

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 477685

Note: I renamed the a function to readPrintLoop as suggested by @SamuelBarr, since that avoids some confusion.

My question is, what is the type of readPrintLoop, and how does the above expression work to continually take user input and print only the numeric part of the input back to the screen?

readPrintLoop has type: readPrintLoop :: IO a so it is an IO. The a can be any type, since we never "return" that value, we will never end this function.

The function is constantly repeated because readPrintLoop is defined in terms of itself. readPrintLoop is defined as:

readPrintLoop :: IO a
readPrintLoop = getLine >>= putStrLn . filter isDigit >> readPrintLoop

We here thus have infinite recursion, since eventually you will run into a, and thus replace that with another getLine >>= putStrLn . filter isDigit >> a and so on.

However, the function >> takes a first monadic value and a second monadic value and returns the second monadic value.

(>>) is equivalent to:

(>>) :: Monad m => m a -> m b -> m b
u >> v = u >>= (\_ -> v)

so the implementation of a is equivalent to:

readPrintLoop :: IO a
readPrintLoop = getLine >>= putStrLn . filter isDigit >>= \_ -> readPrintLoop

Here the underscore variable _ will be passed ().

Upvotes: 6

Will Ness
Will Ness

Reputation: 71119

a  =  getLine >>= putStrLn . filter isDigit

is not "the part of expression".

      getLine >>= putStrLn . filter isDigit

is the part of the expression. And it does not "return IO ()". It has the type IO () (which you've correctly inferred (*)). It is a "monadic value" that you talk about.

Giving it a name, any name,

ioAction :: IO ()
ioAction  =  getLine >>= (putStrLn . filter isDigit)

we end up with

a  =  ioAction >> a 
----------------------------------
 (>>)     :: IO a -> IO b -> IO b
 ioAction :: IO ()
 a        ::         IO b
----------------------------------
 a        ::                 IO b

and everything typechecks.

The semantics of a in

a  =  ((>>) ioAction) a

is defined by the semantics of >>.


(*)

---------------------------------------------------- 
    (>>=)                     :: m a -> (a -> m b) -> m b
    getLine                   :: IO String                   m a
    putStrLn                  ::    String -> IO ()          
    putStrLn . filter isDigit ::    String -> IO ()            a -> m b
----------------------------------------------------        ------------
 getLine >>= (putStrLn . filter isDigit)   :: IO ()          m        b

Upvotes: 5

Related Questions