You misunderstand. IO is just as much a purely functional concept as the rest of the language. notPurelyFunctional is a purely functional function. "notPurelyFunctional 5.0" will behave the same way no matter what you do with it.
You cannot be sure what value1 == value2 will evaluate to even if you assume all the functions (including notPurelyFunctional and (>>=)) are pure(which they are)
One way to make sense of this is to think of 'IO a' as instructions for the computer to compute a value of type a. So you can think of your notPurelyFunctional function as taking a Double, and returning instructions for the computer to compute another Double. notPurelyFunctional 5.0 would then create a value with something like the following information.
let z(which will always be ()) be the result of printing the string "Please enter a number: "
let name be the result of reading a line from stdin
let y be name parsed as a Double
compute and return the value (5.0 + y)
Notice that no matter when or how many times you call notPurelyFunctional with 5.0, the instructions generated will always be exactly the same. When you run your program, the value called main in your program will first be evalutated purely to produce these instructions, and only once these instructions have been (purely) generated will your program be run and these instructions be executed. Thus Haskells purity is preserved at every stage.
Note that this was a very crude way of dealing with how IO behaves and is only meant to be an aid for grasping the concept of IO.
You cannot be sure what value1 == value2 will evaluate to even if you assume all the functions (including notPurelyFunctional and (>>=)) are pure(which they are)
One way to make sense of this is to think of 'IO a' as instructions for the computer to compute a value of type a. So you can think of your notPurelyFunctional function as taking a Double, and returning instructions for the computer to compute another Double. notPurelyFunctional 5.0 would then create a value with something like the following information.
Notice that no matter when or how many times you call notPurelyFunctional with 5.0, the instructions generated will always be exactly the same. When you run your program, the value called main in your program will first be evalutated purely to produce these instructions, and only once these instructions have been (purely) generated will your program be run and these instructions be executed. Thus Haskells purity is preserved at every stage.Note that this was a very crude way of dealing with how IO behaves and is only meant to be an aid for grasping the concept of IO.