liveBook · Manning

IO

As explained in Learn Haskell by Example

An IO action is a Haskell computation that describes interaction with the external world and may produce input/output effects.

IO is the type used to describe Haskell computations that interact with the world outside pure functions. An action such as main :: IO () may perform effects while yielding unit, (), when no meaningful result is needed. Creating an action does not itself perform the interaction; evaluation realizes it. section 3.1 section 3.1.1

Use do notation to sequence actions and pass produced values onward. In a do block, <- evaluates an action and binds its result; the final expression determines the action’s type. putStrLn is a function that produces an IO action, while getLine itself has type IO String. section 3.1.1 section 3.5

Listing 3.1 A simple program that reads a line from the user and prints it
module Main (main) where  #1

main :: IO ()
main = do  #2
  line <- getLine  #3
  putStrLn line  #4

A minimal interactive program reads a line, binds it with <-, and prints it as the final IO () action. section 3.1.1

Keep effects at the boundary of a program:

  • Read arguments, files, and user input in IO actions; print results through actions. section 3.2.2
  • Put parsing, numbering, filtering, formatting, and other transformations in pure functions. section 3.2.2
  • Call pure functions from actions to transform values before output, reducing impure code and making logic easier to reason about and test. section 3.2.1
  • Let pure code choose an action when needed: a Maybe result can select either a help-printing action or an action built from a file path. section 3.4

Number input lines until a blank line

A recursive function can take a counter and return IO (). It reads a line, stops with return () when the line is empty, or prints the numbered line and calls itself with counter + 1. Both branches of the conditional must produce actions of the same type. Here, return wraps a value in IO; it does not exit an action early. section 3.1.2 section 3.1.3

IO is also a monad. do notation is syntactic sugar usable with monads generally, though its monadic details can be deferred while writing basic programs. The Monad interface permits values to be brought into a monadic context with return and sequenced with bind; it deliberately does not provide a general way to extract an IO value into pure code. section 12.1.5 section 12.1.6

Interactions with files, networks, and processes can fail. IO failures may involve exceptions, whereas optional or failed pure computations can be represented with Maybe or Either when their cases are handled directly. section 14.3.3

How Learn Haskell by Example covers it

How deep it goes
Explains action types, do sequencing, recursion, branching, return, pure boundaries, and IO’s monadic role; defers do notation’s general monad details.
Examples
Demonstrates an echo program, uppercase input, a recursive line-numbering interaction, command-line help selection, and GHCi evaluation.
What it assumes
Teaches IO from basic pure-function constraints and introduces unit, do notation, and action types without requiring prior monad knowledge.
What you can do after
Apply it to sequence input and output, combine effects with pure transformations, and stop recursive interactive actions conditionally.
How it connects
Connects IO with pure functions, do notation, recursion, Maybe, Either, Monad, MonadFail, and exceptions.

Also explained in

Compare how 6 books explain IO →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Learn Haskell by Example. The section links point to the parts of the book it draws on.