Why this Haskell code never terminates? - haskell

I recently wrote some Haskell code and it never terminates. After I carefully examined my code, the problem boiled down to the following code piece
main :: IO ()
main = print $ let a = 10 in
let a = a in
a :: Int
I guess this must have something to do with the laziness of Haskell since the same code terminates in OCaml. However, if I wrote the following code instead
main :: IO ()
main = print $ let a = 10 in
let b = a in
b :: Int
the code would have no problem terminating at all. I can't get the reason since in the original code, the two a's should be considered as two different variables. I don't know why the naming of them has anything to do with the semantic of the program.

The issue is that, unlike OCaml, let bindings in Haskell are recursive by default. So let x = x in ... is equivalent to OCaml's let rec x = x in ... and is a circular definition.
This is why shadowing variable names in Haskell (ie defining a multiple times) is considered bad style and even has a compiler warning, which you can turn on with the -Wall flag or more specifically -fwarn-name-shadowing.
This default makes more sense in Haskell than OCaml because, thanks to laziness, circular values (rather than just recursive functions) are actually useful. let x = 1:x gives us an infinite list of 1, which we can use just like a normal list.
At the same time, some people don't like this for basically exactly the reason you ran into here: it's possible to introduce unintuitive infinite loops in your code, which makes some errors and typos harder to track down. This is also confusing because, by necessity, <- bindings in do-notation are not recursive by default, which is a bit inconsistent.

The second binding (a = a) shadows the other one. The first example is (almost) exactly equivalent to
main = print $ let xyz = 10 in
let a = a in
a :: Int
and I hope it's clear why that one doesn't terminate! You can get GHC to warn you about this by using the -fwarn-name-shadowing flag (or by entering :set -fwarn-name-shadowing in GHCi)

Related

Symbol ! in haskell in front of a variable name in a function [duplicate]

I came across the following definition as I try to learn Haskell using a real project to drive it. I don't understand what the exclamation mark in front of each argument means and my books didn't seem to mention it.
data MidiMessage = MidiMessage !Int !MidiMessage
It's a strictness declaration. Basically, it means that it must be evaluated to what's called "weak head normal form" when the data structure value is created. Let's look at an example, so that we can see just what this means:
data Foo = Foo Int Int !Int !(Maybe Int)
f = Foo (2+2) (3+3) (4+4) (Just (5+5))
The function f above, when evaluated, will return a "thunk": that is, the code to execute to figure out its value. At that point, a Foo doesn't even exist yet, just the code.
But at some point someone may try to look inside it, probably through a pattern match:
case f of
Foo 0 _ _ _ -> "first arg is zero"
_ -> "first arge is something else"
This is going to execute enough code to do what it needs, and no more. So it will create a Foo with four parameters (because you can't look inside it without it existing). The first, since we're testing it, we need to evaluate all the way to 4, where we realize it doesn't match.
The second doesn't need to be evaluated, because we're not testing it. Thus, rather than 6 being stored in that memory location, we'll just store the code for possible later evaluation, (3+3). That will turn into a 6 only if someone looks at it.
The third parameter, however, has a ! in front of it, so is strictly evaluated: (4+4) is executed, and 8 is stored in that memory location.
The fourth parameter is also strictly evaluated. But here's where it gets a bit tricky: we're evaluating not fully, but only to weak normal head form. This means that we figure out whether it's Nothing or Just something, and store that, but we go no further. That means that we store not Just 10 but actually Just (5+5), leaving the thunk inside unevaluated. This is important to know, though I think that all the implications of this go rather beyond the scope of this question.
You can annotate function arguments in the same way, if you enable the BangPatterns language extension:
f x !y = x*y
f (1+1) (2+2) will return the thunk (1+1)*4.
A simple way to see the difference between strict and non-strict constructor arguments is how they behave when they are undefined. Given
data Foo = Foo Int !Int
first (Foo x _) = x
second (Foo _ y) = y
Since the non-strict argument isn't evaluated by second, passing in undefined doesn't cause a problem:
> second (Foo undefined 1)
1
But the strict argument can't be undefined, even if we don't use the value:
> first (Foo 1 undefined)
*** Exception: Prelude.undefined
I believe it is a strictness annotation.
Haskell is a pure and lazy functional language, but sometimes the overhead of lazyness can be too much or wasteful. So to deal with that, you can ask to compiler to fully evaluate the arguments to a function instead of parsing thunks around.
There's more information on this page: Performance/Strictness.

Understanding Type of IO () in `let` Expression

Given:
λ: let f = putStrLn "foo" in 42
42
What is f's type? Why does "foo" not get printed before showing the result of 42?
Lastly, why doesn't the following work?
λ: :t f
<interactive>:1:1: Not in scope: ‘f’
What is f's type?
As you have correctly identified, it is IO () which can be thought of as an IO action that returns nothing useful (())
Why does "foo" not get printed before showing the result of 42?
Haskell is lazily evaluated, but even seq is not enough in this case. An IO action will only be performed in the REPL if the expression returns the IO action. An IO action will only be performed in a program if it's returned by main. However, there are ways to get around this limitation.
Lastly, why doesn't the following work?
Haskell's let names a value within the scope of an expression, so after the expression has been evaluated f goes out of scope.
let f = ... simply defines f, and does not "run" anything. It is vaguely similar to a definition of a new function in imperative programming.
Your full code let f = putStrLn "foo" in 42 could be loosely translated to
{
function f() {
print("foo");
}
return 42;
}
You wouldn't expect the above to print anything, right?
By comparison, let f = putStrLn "foo" in do f; f; return 42 is similar to
{
function f() {
print("foo");
}
f();
f();
return 42;
}
The correspondence is not perfect, but hopefully you get the idea.
f will be of type IO ().
"foo" is not printed because f is not 'binded' to real world. (I can't say this is a friendly explanation. If this sounds nonsense, you may want to refer some tutorial to catch the idea of Monad and lazy evaluation).
let name = value in (scope) makes the value available in, but not out of the scope, so :t won't find it in ghci's top level scope.
let without in makes it available to :t (this code is only valid in ghci):
> let f = putStrLn "foo"
> :t f
f :: IO ()
There are two things going on here.
First, consider
let x = sum [1..1000000] in 42
Haskell is lazy. Since we don't actually do anything with x, it is never computed. (Which is just as well, because it would be mildly slow.) Indeed, if you compile this, the compiler will see that x is never used, and delete it (i.e., not generate any compiled code for it).
Second, calling putStrLn does not actually print anything. Rather, it returns IO (), which you can think of as a kind of "I/O command object". Merely having a command object is different from executing the it. By design, the only way to "execute" an I/O command object is to return it from main. At least, it is in a complete program; GHCi has the helpful feature that if you enter an expression that returns an I/O command object, GHCi will execute it for you.
Your expression returns 42; again, f isn't used, so it doesn't do anything.
As chi rightly points out, it's a bit like declaring a local (zero-argument) function but never calling it. You wouldn't expect to see any output.
You can also do something like
actions = [print 5, print 6, print 7, print 8]
This creates a list of I/O command objects. But, again, it does not execute any of them.
Typically when you write a function that does I/O, it's a do-block that chains everything into one giant I/O command object and returns it to the caller. In that case, you don't really need to understand or thing about this distinction between defining a command object and executing it. But the distinction is still there.
It's perhaps easier to see this with a monad that has an explicit run-function. For example, runST takes an ST command object, runs it, and gives you back the answer. But (say) newSTVar, by itself, does nothing but construct an ST command; you have to runST that before anything actually "happens".

What's the reason of 'let rec' for impure functional language OCaml?

In the book Real World OCaml, the authors put why OCaml uses let rec for defining recursive functions.
OCaml distinguishes between nonrecursive definitions (using let) and recursive definitions (using let rec) largely for technical reasons: the type-inference algorithm needs to know when a set of function definitions are mutually recursive, and for reasons that don't apply to a pure language like Haskell, these have to be marked explicitly by the programmer.
What are the technical reasons that enforces let rec while pure functional languages not?
When you define a semantics of function definition, as a language designer, you have choices: either to make the name of the function visible in the scope of its own body, or not. Both choices are perfectly legal, for example C-family languages being far from functional, still do have names of definitions visible in their scope (this also extends to all definitions in C, making this int x = x + 1 legal). OCaml language decides to give us extra flexibility of making the choice by ourselves. And that's really great. They decided to make it invisible by default, a fairly decent solution, since most of the functions that we write are non recursive.
What concerning the cite, it doesn't really correspond to the function definitions – the most common use of the rec keyword. It is mostly about "Why the scope of function definition doesn't extend to the body of the module". This is a completely different question.
After some research I've found a very similar question, that has an answer, that might satisfy you, a cite from it:
So, given that the type checker needs to know about which sets of
definitions are mutually recursive, what can it do? One possibility is
to simply do a dependency analysis on all the definitions in a scope,
and reorder them into the smallest possible groups. Haskell actually
does this, but in languages like F# (and OCaml and SML) which have
unrestricted side-effects, this is a bad idea because it might reorder
the side-effects too. So instead it asks the user to explicitly mark
which definitions are mutually recursive, and thus by extension where
generalization should occur.
Even without any reordering, with arbitrary non-pure expressions, that can occur in the function definition (a side effect of definition, not evaluation) it is impossible to build the dependency graph. Consider demarshaling and executing function from file.
To summarize, we have two usages of let rec construct, one is to create a self recursive function, like
let rec seq acc = function
| 0 -> acc
| n -> seq (acc+1) (n-1)
Another is to define mutually recursive functions:
let rec odd n =
if n = 0 then true
else if n = 1 then false else even (n - 1)
and even n =
if n = 0 then false
else if n = 1 then true else odd (n - 1)
At the first case, there is no technical reasons to stick to one or to another solution. This is just a matter of taste.
The second case is harder. When inferring type you need to split all function definitions into clusters consisting of mutually depending definitions, in order to narrow typing environment. In OCaml it is harder to make, since you need to take into account side-effects. (Or you can continue without splitting it into principal components, but this will lead to another issue – your type system will be more restrictive, i.e., will disallow more valid programs).
But, revisiting the original question and the quote from RWO, I'm still pretty sure that there is no technical reasons for adding the rec flag. Consider, SML that has the same problems, but still has rec enabled by default. There is a technical reason, for let ... and ... syntax for defining a set of mutual recursive functions. In SML this syntax doesn't require us to put the rec flag, in OCaml does, thus giving us more flexibility, like the ability to swap to values with let x = y and y = x expression.
What are the technical reasons that enforces let rec while pure functional languages not?
Recursiveness is a strange beast. It has a relation to purity, but it's a little more oblique than this. To be clear, you could write "alterna-Haskell" which retains its purity, its laziness but does not have recursively bound lets by default and demands some kind of rec marker just as OCaml does. Some would even prefer this.
In essence, there are just many different kinds of "let"s possible. If we compare let and let rec in OCaml we'll see a small difference. In static formal semantics, we might write
Γ ⊢ E : A Γ, x : A ⊢ F : B
-----------------------------
Γ ⊢ let x = E in F : B
which says that if we can prove in a variable environment Γ that E has type A and if we can prove in the same variable environment Γ augmented with x : A that F : B then we can prove that in the variable environment Γ let x = E in F has type B.
The thing to watch is the Γ argument. This is just a list of ("variable name", "value") pairs like [(x, 3); (y, "hello")] and augmenting the list like Γ, x : A just means consing (x, A) on to it (sorry that the syntax is flipped).
In particular, let's write the same formalism for let rec
Γ, x : A ⊢ E : A Γ, x : A ⊢ F : B
-------------------------------------
Γ ⊢ let rec x = E in F : B
In particular, the only difference is that neither of our premises work in the plain Γ environment; both are allowed to assume the existence of the x variable.
In this sense, let and let rec are simply different beasts.
So what does it mean to be pure? At the strictest definition, of which Haskell doesn't even participate, we must eliminate all effects including non-termination. The only way to achieve this is to pull away our ability to write unrestricted recursion and replace it only carefully.
There exist plenty of languages without recursion. Perhaps the most important one is the Simply Typed Lambda Calculus. In it's basic form it is regular lambda calculus but augmented with a typing discipline where types are bit like
type ty =
| Base
| Arr of ty * ty
It turns out that STLC cannot represent recursion---the Y combinator, and all other fixed-point cousin combinators, cannot be typed. Thusly, STLC is not Turing Complete.
It is however uncompromisingly pure. It achieves that purity with the bluntest of instruments, however, by completely outlawing recursion. What we'd really like is some kind of balanced, careful recursion which doesn't lead to non-termination---we'll still be Turing Incomplete, but not so crippled.
Some languages try this game. There are clever ways of adding typed recursion back along a division between data and codata which ensures that you cannot write non-terminating functions. If you're interested, I suggest learning a bit of Coq.
But OCaml's goal (and Haskell's as well) is not to be delicate here. Both languages are uncompromisingly Turing Complete (and therefore "practical"). So let's discuss some more blunt ways of augmenting the STLC with recursion.
The bluntest of the bunch is to add a single built-in function called fix
val fix : ('a -> 'a) -> 'a
or, in more genuine OCaml-y notation which requires eta-expansion
val fix : (('a -> 'b) -> ('a -> 'b)) -> ('a -> 'b)
Now, remember that we're only considering a primitive STLC with fix added. We can indeed write fix (the latter one at least) in OCaml, but that's cheating at the moment. What does fix buy the STLC as a primitive?
It turns out that the answer is: "everything". STLC + Fix (basically a language called PCF) is impure and Turing Complete. It's also simply tremendously difficult to use.
So this is the final hurdle to jump: how do we make fix easier to work with? By adding recursive bindings!
Already, STLC has a let construction. You can think of it as just syntax sugar:
let x = E in F ----> (fun x -> F) (E)
but once we've added fix we also have the power to introduce let rec bindings
let rec x a = E in F ----> (fun x -> F) (fix (fun x a -> E))
At this point it should again be clear: let and let rec are very different beasts. They embody different levels of linguistic power and let rec is a window to allow fundamental impurity through Turing Completeness and its partner-effect non-termination.
So, at the end of the day, it's a little amusing that Haskell, the purer of the two languages, made the interesting choice of abolishing plain let bindings. That's really the only difference: there is no syntax for representing a non-recursive binding in Haskell.
At this point it's essentially just a style decision. The authors of Haskell determined that recursive bindings were so useful that one might as well assume that every binding is recursive (and mutually so, a can of worms ignored in this answer so far).
On the other hand, OCaml gives you to ability to be totally explicit about the kind of binding you choose, let or let rec!
I think this has nothing to do with being purely functional, it is just a design decision that in Haskell you are not allowed to do
let a = 0;;
let a = a + 1;;
whereas you can do it in Caml.
In Haskell this code won't work because let a = a + 1 is interpreted as a recursive definition and will not terminate.
In Haskell you don't have to specify that a definition is recursive simply because you can't create a non-recursive one (so the keyword rec is everywhere but is not written).
I am not an expert, but I'll make a guess until the truly knowledgable guys show up. In OCaml there can be side effects that happen during the definition of a function:
let rec f =
let () = Printf.printf "hello\n" in
fun x -> if x <= 0 then 12 else 1 + f (x - 1)
This means that the order of function definitions must be preserved in some sense. Now imagine that two distinct sets of mutually recursive functions are interleaved. It doesn't seem at all easy for the compiler to preserve the order while processing them as two separate mutually recursive sets of definitions.
The use of `let rec ... and`` means that distinct sets of mutually recursive function definitions can't be interleaved in OCaml as they can in Haskell. Haskell doesn't have side effects (in some sense), so definitions can be freely reordered.
It's not a question of purity, it's a question of specifying what environment the typechecker should check an expression in. It actually gives you more power than you would have otherwise. For example (I'm going to write Standard ML here because I know it better than OCaml, but I believe the typechecking process is pretty much the same for the two languages), it lets you distinguish between these cases:
val foo : int = 5
val foo = fn (x) => if x = foo then 0 else 1
Now as of the second redefinition, foo has the type int -> int. On the other hand,
val foo : int = 5
val rec foo = fn (x) => if x = foo then 0 else 1
does not typecheck, because the rec means that the typechecker has already decided that foo has been rebound to the type 'a -> int, and when it tries to figure out what that 'a needs to be, there is a unification failure because x = foo forces foo to have a numeric type, which it doesn't.
It can certainly "look" more imperative, because the case without rec allows you to do things like this:
val foo : int = 5
val foo = foo + 1
val foo = foo + 1
and now foo has the value 7. That's not because it's been mutated, however --- the name foo has been rebound 3 times, and it just so happens that each of those bindings shadowed a previous binding of a variable named foo. It's the same as this:
val foo : int = 5
val foo' = foo + 1
val foo'' = foo' + 1
except that foo and foo' are no longer available in the environment after the identifier foo has been rebound. The following are also legal:
val foo : int = 5
val foo : real = 5.0
which makes it clearer that what's happening is shadowing of the original definition, rather than a side effect.
Whether or not it's stylistically a good idea to rebind identifiers is questionable -- it can get confusing. It can be useful in some situations (e.g. rebinding a function name to a version of itself that prints debugging output).
I'd say that in OCaml they are trying to make REPL and source files work the same way. So, it's perfectly reasonable to redefine some function in REPL; therefore, they have to allow it in the source as well. Now, if you use the (redefined) function in itself, OCaml needs some way of knowing which of the definitions to use: the previous one or the new one.
In Haskell they've just gave up and accepted that REPL works differentyle from source files.

Evaluation of nullary functions in Haskell

Suppose you have a nullary function in Haskell, which is used several times in the code. Is it always evaluated only once? I already tested the following code:
sayHello :: Int
sayHello = unsafePerformIO $ do
putStr "Hello"
return 42
test :: Int -> [Int]
test 0 = []
test n = (sayHello:(test (n-1)))
When I call test 10, it writes "Hello" only once, so it's indicating the result of function is stored after first evaluation. My question is, is it guaranteed? Will I get the same result across different compilers?
Edit
The reason I used unsafePerformIO is to check whether sayHello is evaluated more than once. I don't use that in my program. Normally I expect sayHello to have exactly the same result every time its evaluated. But it's a time-consuming operation, so I wanted to know if it could be accessed this way, or if it should be passed as an argument wherever it's needed to ensure it is not evaluated multiple times, i.e.:
test _ 0 = []
test s n = (s:(test (n-1)))
...
test sayHello 10
According to the answers this should be used.
There is no such thing as a nullary function. A function in Haskell has exactly one argument, and always has type ... -> .... sayHello is a value -- an Int -- but not a function. See this article for more.
On guarantees: No, you don't really get any guarantees. The Haskell report specifies that Haskell is non-strict -- so you know what value things will eventually reduce to -- but not any particular evaluation strategy. The evaluation strategy GHC generally uses is lazy evaluation, i.e. non-strict evaluation with sharing, but it doesn't make strong guarantees about that -- the optimizer could shuffle your code around so that things are evaluated more than once.
There are also various exceptions -- for example, foo :: Num a => a is polymorphic, so it probably won't be shared (it's compiled to an actual function). Sometimes a pure value might be evaluated by more than one thread at the same time (that won't happen in this case because unsafePerformIO explicitly uses noDuplicate to avoid it). So when you program, you can generally expect laziness, but if you want any sort of guarantees you'll have to be very careful. The Report itself won't really give you anything on how your program is evaluated.
unsafePerformIO gives you even less in the way of guarantees, of course. There's a reason it's called "unsafe".
Top level no-argument functions like sayHello are called Constant Applicative Forms and are always memoised (atleast in GHC - see http://www.haskell.org/ghc/docs/7.2.1/html/users_guide/profiling.html). You would have to resort to tricks like passing in dummy arguments and turning optimisations off to not share a CAF globally.
Edit: quote from the link above -
Haskell is a lazy language, and certain expressions are only ever
evaluated once. For example, if we write:
x = nfib 25 then x will only be evaluated once (if at all), and
subsequent demands for x will immediately get to see the cached result.
The definition x is called a CAF (Constant Applicative Form), because
it has no arguments.
If you do want "Hello" printed n times, you need to remove the unsafePermformIO, so the runtime will know it can't optimize away repeated calls to putStr. I'm not clear whether you want to return the list of int, so I've written two versions of test, one of which returns (), one [Int].
sayHello2 :: IO Int
sayHello2 = do
putStr "Hello"
return 42
test2 :: Int -> IO ()
test2 0 = return ()
test2 n = do
sayHello2
test2 (n-1)
test3 :: Int -> IO [Int]
test3 0 = return []
test3 n = do
r <- sayHello2
l <- test3 (n-1)
return $ r:l

Is Haskell truly pure (is any language that deals with input and output outside the system)?

After touching on Monads in respect to functional programming, does the feature actually make a language pure, or is it just another "get out of jail free card" for reasoning of computer systems in the real world, outside of blackboard maths?
EDIT:
This is not flame bait as someone has said in this post, but a genuine question that I am hoping that someone can shoot me down with and say, proof, it is pure.
Also I am looking at the question with respect to other not so pure Functional Languages and some OO languages that use good design and comparing the purity. So far in my very limited world of FP, I have still not groked the Monads purity, you will be pleased to know however I do like the idea of immutability which is far more important in the purity stakes.
Take the following mini-language:
data Action = Get (Char -> Action) | Put Char Action | End
Get f means: read a character c, and perform action f c.
Put c a means: write character c, and perform action a.
Here's a program that prints "xy", then asks for two letters and prints them in reverse order:
Put 'x' (Put 'y' (Get (\a -> Get (\b -> Put b (Put a End)))))
You can manipulate such programs. For example:
conditionally p = Get (\a -> if a == 'Y' then p else End)
This is has type Action -> Action - it takes a program and gives another program that asks for confirmation first. Here's another:
printString = foldr Put End
This has type String -> Action - it takes a string and returns a program that writes the string, like
Put 'h' (Put 'e' (Put 'l' (Put 'l' (Put 'o' End)))).
IO in Haskell works similarily. Although executing it requires performing side effects, you can build complex programs without executing them, in a pure way. You're computing on descriptions of programs (IO actions), and not actually performing them.
In language like C you can write a function void execute(Action a) that actually executed the program. In Haskell you specify that action by writing main = a. The compiler creates a program that executes the action, but you have no other way to execute an action (aside dirty tricks).
Obviously Get and Put are not only options, you can add many other API calls to the IO data type, like operating on files or concurrency.
Adding a result value
Now consider the following data type.
data IO a = Get (Char -> Action) | Put Char Action | End a
The previous Action type is equivalent to IO (), i.e. an IO value which always returns "unit", comparable to "void".
This type is very similar to Haskell IO, only in Haskell IO is an abstract data type (you don't have access to the definition, only to some methods).
These are IO actions which can end with some result. A value like this:
Get (\x -> if x == 'A' then Put 'B' (End 3) else End 4)
has type IO Int and is corresponding to a C program:
int f() {
char x;
scanf("%c", &x);
if (x == 'A') {
printf("B");
return 3;
} else return 4;
}
Evaluation and execution
There's a difference between evaluating and executing. You can evaluate any Haskell expression, and get a value; for example, evaluate 2+2 :: Int into 4 :: Int. You can execute Haskell expressions only which have type IO a. This might have side-effects; executing Put 'a' (End 3) puts the letter a to screen. If you evaluate an IO value, like this:
if 2+2 == 4 then Put 'A' (End 0) else Put 'B' (End 2)
you get:
Put 'A' (End 0)
But there are no side-effects - you only performed an evaluation, which is harmless.
How would you translate
bool comp(char x) {
char y;
scanf("%c", &y);
if (x > y) { //Character comparison
printf(">");
return true;
} else {
printf("<");
return false;
}
}
into an IO value?
Fix some character, say 'v'. Now comp('v') is an IO action, which compares given character to 'v'. Similarly, comp('b') is an IO action, which compares given character to 'b'. In general, comp is a function which takes a character and returns an IO action.
As a programmer in C, you might argue that comp('b') is a boolean. In C, evaluation and execution are identical (i.e they mean the same thing, or happens simultaneously). Not in Haskell. comp('b') evaluates into some IO action, which after being executed gives a boolean. (Precisely, it evaluates into code block as above, only with 'b' substituted for x.)
comp :: Char -> IO Bool
comp x = Get (\y -> if x > y then Put '>' (End True) else Put '<' (End False))
Now, comp 'b' evaluates into Get (\y -> if 'b' > y then Put '>' (End True) else Put '<' (End False)).
It also makes sense mathematically. In C, int f() is a function. For a mathematician, this doesn't make sense - a function with no arguments? The point of functions is to take arguments. A function int f() should be equivalent to int f. It isn't, because functions in C blend mathematical functions and IO actions.
First class
These IO values are first-class. Just like you can have a list of lists of tuples of integers [[(0,2),(8,3)],[(2,8)]] you can build complex values with IO.
(Get (\x -> Put (toUpper x) (End 0)), Get (\x -> Put (toLower x) (End 0)))
:: (IO Int, IO Int)
A tuple of IO actions: first reads a character and prints it uppercase, second reads a character and returns it lowercase.
Get (\x -> End (Put x (End 0))) :: IO (IO Int)
An IO value, which reads a character x and ends, returning an IO value which writes x to screen.
Haskell has special functions which allow easy manipulation of IO values. For example:
sequence :: [IO a] -> IO [a]
which takes a list of IO actions, and returns an IO action which executes them in sequence.
Monads
Monads are some combinators (like conditionally above), which allow you to write programs more structurally. There's a function that composes of type
IO a -> (a -> IO b) -> IO b
which given IO a, and a function a -> IO b, returns a value of type IO b. If you write first argument as a C function a f() and second argument as b g(a x) it returns a program for g(f(x)). Given above definition of Action / IO, you can write that function yourself.
Notice monads are not essential to purity - you can always write programs as I did above.
Purity
The essential thing about purity is referential transparency, and distinguishing between evaluation and execution.
In Haskell, if you have f x+f x you can replace that with 2*f x. In C, f(x)+f(x) in general is not the same as 2*f(x), since f could print something on the screen, or modify x.
Thanks to purity, a compiler has much more freedom and can optimize better. It can rearrange computations, while in C it has to think if that changes meaning of the program.
It is important to understand that there is nothing inherently special about monads – so they definitely don’t represent a “get out of jail” card in this regard. There is no compiler (or other) magic necessary to implement or use monads, they are defined in the purely functional environment of Haskell. In particular, sdcvvc has shown how to define monads in purely functional manner, without any recourses to implementation backdoors.
What does it mean to reason about computer systems "outside of blackboard maths"? What kind of reasoning would that be? Dead reckoning?
Side-effects and pure functions are a matter of point of view. If we view a nominally side-effecting function as a function taking us from one state of the world to another, it's pure again.
We can make every side-effecting function pure by giving it a second argument, a world, and requiring that it pass us a new world when it is done. I don't know C++ at all anymore but say read has a signature like this:
vector<char> read(filepath_t)
In our new "pure style", we handle it like this:
pair<vector<char>, world_t> read(world_t, filepath_t)
This is in fact how every Haskell IO action works.
So now we've got a pure model of IO. Thank goodness. If we couldn't do that then maybe Lambda Calculus and Turing Machines are not equivalent formalisms and then we'd have some explaining to do. We're not quite done but the two problems left to us are easy:
What goes in the world_t structure? A description of every grain of sand, blade of
grass, broken heart and golden sunset?
We have an informal rule that we use a world only once -- after every IO operation, we
throw away the world we used with it. With all these worlds floating around, though,
we are bound to get them mixed up.
The first problem is easy enough. As long as we do not allow inspection of the world, it turns out we needn't trouble ourselves about storing anything in it. We just need to ensure that a new world is not equal to any previous world (lest the compiler deviously optimize some world-producing operations away, like it sometimes does in C++). There are many ways to handle this.
As for the worlds getting mixed up, we'd like to hide the world passing inside a library so that there's no way to get at the worlds and thus no way to mix them up. Turns out, monads are a great way to hide a "side-channel" in a computation. Enter the IO monad.
Some time ago, a question like yours was asked on the Haskell mailing list and there I went in to the "side-channel" in more detail. Here's the Reddit thread (which links to my original email):
http://www.reddit.com/r/haskell/comments/8bhir/why_the_io_monad_isnt_a_dirty_hack/
I'm very new to functional programming, but here's how I understand it:
In haskell, you define a bunch of functions. These functions don't get executed. They might get evaluated.
There's one function in particular that gets evaluated. This is a constant function that produces a set of "actions." The actions include the evaluation of functions and performing of IO and other "real-world" stuff. You can have functions that create and pass around these actions and they will never be executed unless a function is evaluated with unsafePerformIO or
they are returned by the main function.
So in short, a Haskell program is a function, composed of other functions, that returns an imperative program. The Haskell program itself is pure. Obviously, that imperative program itself can't be. Real-world computers are by definition impure.
There's a lot more to this question and a lot of it is a question of semantics (human, not programming language). Monads are also a bit more abstract than what I've described here. But I think this is a useful way of thinking about it in general.
I think of it like this: Programs have to do something with the outside world to be useful. What's happening (or should be happening) when you write code (in any language) is that you strive to write as much pure, side-effect-free code as possible and corral the IO into specific places.
What we have in Haskell is that you're pushed more in this direction of writing to tightly control effects. In the core and in many libraries there is an enormous amount of pure code as well. Haskell is really all about this. Monads in Haskell are useful for a lot of things. And one thing they've been used for is containment around code that deals with impurity.
This way of designing together with a language that greatly facilitates it has an overall effect of helping us to produce more reliable work, requiring less unit testing to be clear on how it behaves, and allowing more re-use through composition.
If I understand what you're saying correctly, I don't see this as a something fake or only in our minds, like a "get out of jail free card." The benefits here are very real.
For an expanded version of sdcwc's sort of construction of IO, one can look at the IOSpec package on Hackage: http://hackage.haskell.org/package/IOSpec
Is Haskell truly pure?
In the absolute sense of the term: no.
That solid-state Turing machine on which you run your programs - Haskell or otherwise - is a state-and-effect device. For any program to use all of its "features", the program will have to resort to using state and effects.
As for all the other "meanings" ascribed to that pejorative term:
To postulate a state-less model of computation on top of a machinery whose most eminent characteristic is state, seems to be an odd idea, to say the least. The gap between model and machinery is wide, and therefore costly to bridge. No hardware support feature can wash this fact aside: It remains a bad idea for practice.
This has in due time also been recognized by the protagonists of functional languages. They have introduced state (and variables) in various tricky ways. The purely functional character has thereby been compromised and sacrificed. The old terminology has become deceiving.
Niklaus Wirth
Does using monadic types actually make a language pure?
No. It's just one way of using types to demarcate:
definitions that have no visible side-effects at all - values;
definitions that potentially have visible side-effects - actions.
You could instead use uniqueness types, just like Clean does...
Is the use of monadic types just another "get out of jail free card" for reasoning of computer systems in the real world, outside of blackboard maths?
This question is ironic, considering the description of the IO type given in the Haskell 2010 report:
The IO type serves as a tag for operations (actions) that interact with the outside world. The IO type is abstract: no constructors are visible to the user. IO is an instance of the Monad and Functor classes.
...to borrow the parlance of another answer:
[…] IO is magical (having an implementation but no denotation) […]
Being abstract, the IO type is anything but a "get out of jail free card" - intricate models involving multiple semantics are required to account for the workings of I/O in Haskell. For more details, see:
Tackling the Awkward Squad: … by Simon Peyton Jones;
The semantics of fixIO by Levent Erk, John Launchbury and Andrew Moran.
It wasn't always like this - Haskell originally had an I/O mechanism which was at least partially-visible; the last language version to have it was Haskell 1.2. Back then, the type of main was:
main :: [Response] -> [Request]
which was usually abbreviated to:
main :: Dialogue
where:
type Dialogue = [Response] -> [Request]
and Response along with Request were humble, albeit large datatypes:
The advent of I/O using the monadic interface in Haskell changed all that - no more visible datatypes, just an abstract description. As a result, how IO, return, (>>=) etc are really defined is now specific to each implementation of Haskell.
(Why was the old I/O mechanism abandoned? "Tackling the Awkward Squad" gives an overview of its problems.)
These days, the more pertinent question should be:
Is I/O in your implementation of Haskell referentially transparent?
As Owen Stephens notes in Approaches to Functional I/O:
I/O is not a particularly active area of research, but new approaches are still being discovered […]
The Haskell language may yet have a referentially-transparent model for I/O which doesn't attract so much controversy...
No, it isn't. IO monad is impure because it has side effects and mutable state (the race conditions are possible in Haskell programs so ? eh ... pure FP language don't know something like "race condition"). Really pure FP is Clean with uniqueness typing, or Elm with FRP (functional reactive programing) not Haskell. Haskell is one big lie.
Proof :
import Control.Concurrent
import System.IO as IO
import Data.IORef as IOR
import Control.Monad.STM
import Control.Concurrent.STM.TVar
limit = 150000
threadsCount = 50
-- Don't talk about purity in Haskell when we have race conditions
-- in unlocked memory ... PURE language don't need LOCKING because
-- there isn't any mutable state or another side effects !!
main = do
hSetBuffering stdout NoBuffering
putStr "Lock counter? : "
a <- getLine
if a == "y" || a == "yes" || a == "Yes" || a == "Y"
then withLocking
else noLocking
noLocking = do
counter <- newIORef 0
let doWork =
mapM_ (\_ -> IOR.modifyIORef counter (\x -> x + 1)) [1..limit]
threads <- mapM (\_ -> forkIO doWork) [1..threadsCount]
-- Sorry, it's dirty but time is expensive ...
threadDelay (15 * 1000 * 1000)
val <- IOR.readIORef counter
IO.putStrLn ("It may be " ++ show (threadsCount * limit) ++
" but it is " ++ show val)
withLocking = do
counter <- atomically (newTVar 0)
let doWork =
mapM_ (\_ -> atomically $ modifyTVar counter (\x ->
x + 1)) [1..limit]
threads <- mapM (\_ -> forkIO doWork) [1..threadsCount]
threadDelay (15 * 1000 * 1000)
val <- atomically $ readTVar counter
IO.putStrLn ("It may be " ++ show (threadsCount * limit) ++
" but it is " ++ show val)

Resources