Is print
in Haskell a pure function; why or why not? I'm thinking it's not, because it does not always return the same value as pure functions should.
-
6What does `print` returns? – Willem Van Onsem Nov 16 '17 at 17:55
-
1All the builtin impure functions have the word `unsafe` in the name. So `print` is pure. It returns the same result given the same parameter. – 4castle Nov 16 '17 at 17:58
-
@4castle Not necessarily, usually `unsafe` is about the fact that the function is not total. – freestyle Nov 16 '17 at 18:00
-
1@freestyle Well, that is saying that there are other functions that also have `unsafe` in the name. That's not really in opposition to what 4castle said. I'm also not sure of any *builtin* functions that use the convention you're talking about (only builtin functions of the sort 4castle mentioned, like `unsafeInterleaveIO` and `reallyUnsafePtrEquality#`). – David Young Nov 16 '17 at 18:05
-
@DavidYoung Yes, I didn't say exactly, I wanted to say that `unsafe` doesn't always say that the function isn't pure. Sometimes, it's about that the function doesn't check something. – freestyle Nov 16 '17 at 18:15
-
1Possible duplicate of [Why monads? How does it resolve side-effects?](https://stackoverflow.com/questions/7840126/why-monads-how-does-it-resolve-side-effects) – jberryman Nov 16 '17 at 21:32
3 Answers
A value of type IO Int
is not really an Int
. It's more like a piece of paper which reads "hey Haskell runtime, please produce an Int
value in such and such way". The piece of paper is inert and remains the same, even if the Int
s eventually produced by the runtime are different.
You send the piece of paper to the runtime by assigning it to main
. If the IO
action never comes in the way of main
and instead languishes inside some container, it will never get executed.
Functions that return IO
actions are pure like the others. They always return the same piece of paper. What the runtime does with those instructions is another matter.
If they weren't pure, we would have to think twice before changing
foo :: (Int -> IO Int) -> IO Int
foo f = liftA2 (+) (f 0) (f 0)
to:
foo :: (Int -> IO Int) -> IO Int
foo f = let x = f 0 in liftA2 (+) x x

- 15,898
- 3
- 42
- 75

- 26,936
- 4
- 45
- 95
-
At runtime, `IO X` and `X` are really represented the same way. It is just that the compiler knows special things about how `IO X` might behave (and special things about how pure values behave - assumptions which can be violated!); and it generates code which is optimized using these assumptions. The view of IO as instructions (i.e. "pieces of paper") is still useful; but it shouldn't be thought of as relating to 'values at runtime' - rather to 'values as logical objects'. – user2407038 Nov 16 '17 at 23:40
-
3@user2407038 In GHC at least, `IO X` has [a very different representation](https://hackage.haskell.org/package/base-4.10.0.0/docs/src/GHC.Base.html#line-1197) than `X`. – Daniel Wagner Nov 17 '17 at 00:38
If you just read the Tag of pure-function (A function that always evaluates to the same result value given the same argument value(s) and that does not cause any semantically observable side effect or output, such as mutation of mutable objects or output to I/O devices.) and then Think in the type of print:
putStrLn :: String -> IO ()
You will find a trick there, it always returns IO ()
, so... No, it produces effects. So in terms of Referential Transparency is not pure
For example, getLine
returns IO String
but it is also a pure function. (@interjay contribution), What I'm trying to say, is that the answer depends very close of the question:
On matter of value, IO ()
will always be the same IO ()
value for the same input.
And
On matter of execution, it is not pure because the execution of that
IO ()
could have side effects (put an string in the screen, in this
case looks so innocent, but some IO could lunch nuclear bombs, and
then return the Int 42)
You could understand better with the nice approach of @Ben here:
"There are several ways to explain how you're "purely" manipulating the real world. One is to say that IO is just like a state monad, only the state being threaded through is the entire world outside your program;= (so your Stuff -> IO DBThing function really has an extra hidden argument that receives the world, and actually returns a DBThing along with another world; it's always called with different worlds, and that's why it can return different DBThing values even when called with the same Stuff). Another explanation is that an IO DBThing value is itself an imperative program; your Haskell program is a totally pure function doing no IO, which returns an impure program that does IO, and the Haskell runtime system (impurely) executes the program it returns."
And @Erik Allik:
So Haskell functions that return values of type IO a, are actually not the functions that are being executed at runtime — what gets executed is the IO a value itself. So these functions actually are pure but their return values represent non-pure computations.
You can found them here Understanding pure functions in Haskell with IO

- 15,898
- 3
- 42
- 75
-
-
1Obviously it always returns `IO ()` since that is required by the type, but the question is whether it always returns the _same_ value of `IO ()`. – Lee Nov 16 '17 at 18:03
-
-
Yes it is a value, but the question is whether `print` always returns the same value. It's not enough for it to just have the correct type. – Lee Nov 16 '17 at 18:05
-
3@DamianLattenero "IO () Is a value itself" No, it's not. There are many different values of type `IO ()` and even `print` can produce different values of that type (if you pass it different arguments). Otherwise all print statements would print the same thing. – sepp2k Nov 16 '17 at 18:06
-
Isn't the point of a pure function to return the same thing *given the same inputs?* (parameters) Otherwise all functions would be useless – HFBrowning Nov 16 '17 at 18:07
-
@sepp2k `() :: ()` unit value, isn't a value? and always the same value? Maybe I'm missing something – developer_hatch Nov 16 '17 at 18:13
-
@DavidYoung Okay, thanks. I think this the OP's question is rather deeper than it appears at first blush - so perhaps some elaboration could be useful. Because it would seem to me that this is an edge case in Haskell where the developers tried to make an inherently impure activity as pure as possible. Since the obvious answer from almost any other language would be "of course not, the point of printing is to get a side effect". – HFBrowning Nov 16 '17 at 18:14
-
1@HFBrowning It's kind of like a form of metaprogramming, in some ways. The "pure" parts of a Haskell program construct an IO action (out of smaller IO actions) which is then executed. – David Young Nov 16 '17 at 18:15
-
@DavidYoung sure, but always `()` value is returned... so... is pure at the end. – developer_hatch Nov 16 '17 at 18:17
-
1@DamianLattenero The `()` is not returned. The `IO` action is returned. This particular `IO` action gives you back a `()`, but it could give back something else. For example, you can have an IO action that reads a file and it can give back a `String` that is different if the file is changed, each time you run it. But you aren't calling a function there. You are running an IO action. It might sound like a matter of "semantics" (in the sense of English), but this distinction is actually pretty deeply built into the language itself. – David Young Nov 16 '17 at 18:18
-
4@DamianLattenero Yes, `()` is a value of type `()` and it's the only value of type `()`. But print does not give you a value of type `()`, it gives you a value of type `IO ()`, of which there are many (in fact infinitely many) different values and `()` isn't one of them. For example the values produced by `print "hello"` and `print "world"` are different - otherwise `main = print "hello"` and `main = print "world"` would need to behave the same, as `main` would have the same value in both. – sepp2k Nov 16 '17 at 18:19
-
@sepp2k but, for the same String, for example, "hello", it will return always the same `IO ()` value? or could be different? if I give "hello", could some time prints "world" or something? – developer_hatch Nov 16 '17 at 18:24
-
3It always returns the same IO action for the same input, but this has nothing to do with the fact that it returns `IO ()`. For example, `getLine` returns `IO String` but it is also a pure function. – interjay Nov 16 '17 at 18:31
-
@interjay Thanks so much! now it get alll clear, I edited thanks to you, a lot. I had it misunderstanding – developer_hatch Nov 16 '17 at 18:33
-
-
1@DamianLattenero Technically, `getLine` is not a pure function since it is not even a function, it is a value of type `IO ()`. This roughly correspond to what in imperative languages would be modelled as a zero-args "void" function, but in Haskell is not a function. – chi Nov 16 '17 at 18:42
-
@chi I'm totally agree with you, I was doing more research on my own, and finally add info that I found here and there, and finally updated my answer in your line of thinking – developer_hatch Nov 17 '17 at 13:26
-
`putStrLn "Hi" :: IO ()` is a pure value that *represents* an I/O action of printing the string `"Hi\n"` at stdout. It might or [might not ever](https://stackoverflow.com/q/47336203/i#comment81633766_47338028) be actually executed. `let x = print "1" in x >> x` and `print "1" >> print "1"` are fully interchangeable. This is the definition of being *referentially transparent* indeed. Where your answer says otherwise it is incorrect. Haskell is pure because we never execute; we just manipulate the pure values which represent executable actions. It's a pretense, but a mathematically sound one. – Will Ness Jul 20 '19 at 10:39
Yes, print
is a pure function. The value it returns has type IO ()
, which you can think of as a bunch of code that outputs the string you passed in. For each string you pass in, it always returns the same code.

- 5,312
- 4
- 22
- 49