Hacker News new | ask | show | jobs
by willtim 3247 days ago
> As soon as you have side-effects (an IO is a side-effect) you can through your assumptions about "strict conformation to definition" out of the window

Again, you are unfortunately quite wrong. You do not understand the IO Monad. No IO is ever performed in any code written inside the IO monad (unless using unsafePerformIO).

Please take some time to fully understand Haskell before criticising it so openly on a public forum. Perhaps then it might not all seem rather pointless.

2 comments

So, you're telling me that Haskell never does any output and never reads any input.

In this case (an only in this case) would it strictly conform to FP definition.

Haskell is used to wire-up the IO actions, they are then delivered to the runtime via the main definition. The runtime performs the IO actions.
Indeed Haskell the language doesn't do any IO. Instead, it creates a tuple containing

* a description of the action to execute (e.g. read line from STDIN)

* a function that will take the result of the previous action (e.g. the line) and return the next action to execute (e.g. writeLine)

  [readLine, \line -> writeLine(line)]
This main action is just a description, the runtime itself takes it, does the actual IO described in the first part of this tuple, evaluates the second (function) part of the tuple with the result of that IO, receives a new pair of action/function, does the action's IO part, evaluates the new function and so on until it gets a nil (end of the "linked list" so to speak)

You could imagine this as a linked list of actions, where the "link" is actually a pure function you call with the result of execution the first part to get the rest of the list (or nil to terminate). This is still pure because the action itself doesn't do anything. If you return an action from a function, it doesn't actually execute, its just a value to be interpreted.

Does that make a real difference or is it just theoretical "purity"? Yes it does make a difference.

For example, if you create two action values, you haven't actually run anything yet, just created descriptions of actions. You could put them in a list and create an action description that will tell the runtime to run them in parallel, for example using: https://hackage.haskell.org/package/parallel-io-0.3.3/docs/C... ... or in sequence https://hackage.haskell.org/package/base-4.10.0.0/docs/Prelu...

For refactoring, it means that you can still take functions that return actions and substitute them with their values, e.g. if you have

  readItems 0 = return []
  readItems n = do
    x <- readLine
    y <- readItems (n - 1)
    x :: y

  main :: IO
    items <- readItems 3
    putStrLn "The first item is " ++ (head items)

you could pull (readItems 3) out of main!

  read3Items = readItems 3
  
  main :: IO
    items <- read3Items
    putStrLn ...
and everything is exactly the same, since all you've pulled out is a description of an action. Equational reasoning (you can substitute an equation with its result) still works - which is great for refactoring!
Basically, the moment you have

  readFile  :: FilePath -> IO String
  writeFile :: FilePath -> String -> IO ()
and any function invoking those two (and any functions invoking these function etc. etc.) your "haskell strictly conforms to FP definition" flies out of the window.

And yes: I used the term "IO monad" incorrectly.

These functions do not perform IO, they return IO actions that can be further composed. They are invoked from other functions that also return IO actions, again no IO is actually performed until the top-level final composite action is run by the runtime.

All composition of IO actions is performed with full referential transparency and adherence to the Wikipedia definition.

Potato potato. In the end, when the program is run, functions will be run, and side-effects will be executed.

Moreover, if you invoke these functions multiple times they will produce different results.

Hence, no strict adherence to FP principles.

> Moreover, if you invoke these functions multiple times they will produce different results

No this isn't true! Again, you clearly do not yet understand Monads. Please read Phil Wadler's paper.

What you have successfully demonstrated, is that the JavaScript snippets you have been advocating are not sufficient to understand Monads.

> if you invoke these functions multiple times they will produce different results.

the io monad is a pure function that produces impure code for the haskell runtime to execute (this isn't exactly accurate, but i think is an okay way to think about it). It will always produce the same impure code, and so is itself pure.

Riight. The "Platonic ideal" again. "It's not the language it's the runtime!"