3 ms·
In other languages we can do a poor man’s IO with a function like: () => console.log(“abc”) Is this really so different from IO everywhere in Haskell?
by fire_lake 2y ago
In other languages we can do a poor man’s IO with a function like:
() => console.log(“abc”)
Is this really so different from IO everywhere in Haskell?
- mrkeen 2y agoWhen you express it has "Haskell has the IO monad" and "Haskell has the Maybe monad", it's no biggie because other languages have them. All Java Objects might or might not be there (so they all implement Maybe). And all Java methods might or might not do IO, so they all implement IO. The real sell is: Haskell objects which are not Maybe are definitely there. Functions which are not IO will always give the same input for the same output.
- corank 2y agoI think as long as the code sticks to the discipline of never actually doing I/O but only manipulating functions that perform them it would basically be doing the same thing as IO monads in Haskell. So print(s) returns a function that when called prints s. Then there needs to be function that joins those functions, so print(a); print(b) evaluates to a function that once called prints out a and then b. What makes Haskell special in my opinion is 1) it generalises this way of achieving "stateful" functions, 2) enforces such discipline for you and makes sure calling functions never produces side effects, and 3) some syntactic sugar (do, <-, etc) to make it easier to write this kind of code. Also note that the above example only does output which would be the easier case. When it comes to code with input, there will suddenly be values which are unavailable until some side effects have been made, so the returned functions will also need to encode how those values are to be obtained and used, which complicates things further.
- deleted 2y ago[deleted]
- lucasoshiro 2y ago> Is this really so different from IO everywhere in Haskell? It's a starting point. You'll have to somehow chain (e.g. you want to print "def" after "abc", how would you do that?). You'll also need to put a value into your IO, e.g. if you are inside that IO, all the computations will need to produce IO. If you solve those things, you'll have a Monad. But, wait! You're in JS, right? You have IO Monads there, perhaps only don't know yet. They are the JS Promises! Look this: // assuming that you have a sync input function, that receives a string from stdin and returns it let input_str = new Promise((resolve, reject) => resolve(input()); let input_int = input_str.then(s => parseInt(s)); let square = input_int.then(n => n * n); square.then(sq => console.log(sq)); If you want to proceed with your poor man's IO, you'll need to implement your "then". Going further, the equivalent in Haskell (not the best code, though) to that is: main = result where input_str = getLine input_int = input_str >>= \s -> return (read s) :: IO Int square = input_int >>= \n -> return (n * n) result = square >>= \sq -> putStrLn (show sq) Ok, but Haskell has a syntax for cleaning that, called do notation: main = do input_str <- getLine let input_int = read input_str :: Int let square = input_int * input_int putStrLn (show square) And JS? JS has also its syntax, using await. Just like Haskell that it only works inside the do notation, in JS it will only work inside async functions: let input_str = await new Promise((resolve, reject) => resolve(input())); let input_int = parseInt(input_str); let square = input_int * input_int; console.log(square);
- tel 2y agoA function from a fixed input is a monad (called the “Reader” monad). If you constrain all IO to happen underneath that function then it will be deferred until you evaluate the result. In those senses, these are the same. You can emulate the IO monad in this way. Haskell provides guarantees that make this stronger. There is no way to perform IO-like side effects except via the IO monad. And no way to “evaluate” the IO monad except to declare it as your main entry point, compile, and hit play. (Except unsafePerformIO, of course, the highly discouraged escape hatch). These restrictions are actually what makes the use of the IO monad powerful. As you show, it’s easy to “add” it to a language, and also almost valueless. The value is in removing everything that’s not in the IO monad.
- tome 2y agoThat IO is roughly the same. The point of Haskell is not to "have IO". It's to know that when something is _not_ in IO, it's pure. _That_ is what other languages don't have. (Although they could, as far as I know. It's a _restriction_ on exposed primitives, not a feature.)