Haskell handles I/O operations in a purely functional way by utilizing the ‘IO‘ monad. Although Haskell is a purely functional language, the existence of I/O is essential for any practical programs. To accommodate both functional purity and side effects caused by I/O operations, Haskell uses the concept of monads, specifically the ‘IO‘ monad to model and encapsulate side effects in a controlled manner.
A monad is a design pattern that allows a program to sequence computations and combine them with other computations while maintaining functional purity. The ‘IO‘ monad, in particular, is designed for encapsulating side effects like reading from or writing to files, getting user input, printing on the screen, and so on.
In Haskell, the main function has the type ‘IO ()‘. Any function that performs I/O must return a value inside the ‘IO‘ monad, indicating that the function is impure and has side effects. The ‘IO‘ monad allows Haskell programs to sequence I/O actions while preserving referential transparency and other benefits of functional programming.
Here is an example of a simple Haskell program using the ‘IO‘ monad to get user input and print a greeting:
main :: IO ()
main = do
putStrLn "What is your name?"
name <- getLine -- getLine :: IO String
putStrLn ("Hello, " ++ name ++ "!")
In this example, the ‘putStrLn‘ and ‘getLine‘ functions are both in the ‘IO‘ monad. The ‘do‘ notation provides a convenient syntax for chaining together I/O actions as well as binding values obtained from them.
It is important to note that the ‘IO‘ monad only encapsulates and manages the side effects, but it does not actually "run" or "execute" the I/O actions. The runtime system ultimately handles the execution of I/O actions, and Haskell programs provide a description of the desired sequence of I/O actions.
In summary, the ‘IO‘ monad in Haskell allows handling of I/O operations in a purely functional way while preserving referential transparency and other benefits of functional programming languages. The ‘IO‘ monad encapsulates side effects and makes it possible to sequence and compose I/O actions in a controlled and principled manner.