Я так понимаю, вы пытаетесь увидеть, как связать результат "putStrLn". Ответ в типе putStrLn:
putStrLn :: String -> IO ()
Помните, что "()" - это тип единицы измерения, который имеет одно значение (также пишется "()"). Таким образом, вы можете связать это точно так же. Но так как вы не используете его, вы привязываете его к значению «пофиг»:
getLine >>= \line1 ->
putStrLn "enter second line" >>= \_ ->
getline >>= \line2 ->
return (line1, line2)
Как это происходит, уже определен оператор для игнорирования возвращаемого значения, ">>". Так что вы можете просто переписать это как
getLine >>= \line1 ->
putStrLn "enter second line" >>
getline >>= \line2 ->
return (line1, line2)
Я не уверен, пытаетесь ли вы также понять, как операторы связывания связаны последовательно. Чтобы увидеть это, позвольте мне поставить неявные скобки и дополнительные отступы в приведенном выше примере:
getLine >>= (\line1 ->
putStrLn "enter second line" >> (
getline >>= (\line2 ->
return (line1, line2))))
Каждый оператор связывания связывает значение слева с функцией справа. Эта функция состоит из всех остальных строк в предложении «do». Таким образом, переменная, связанная через лямбду («line1» в первой строке), находится в области действия для всего остального предложения.