I/O is by definition not pure, but the use of monads allow a strict separation between the pure and impure parts of the code. I guess you can say that monads allow you to have a guaranteed pure sublanguage.
I/O is by definition not pure, but the use of monads allow a strict separation between the pure and impure parts of the code. I guess you can say that monads allow you to have a guaranteed pure sublanguage.
The whole premise is that you end up with some main function which is a description of side effects, but you still have referential transparency and the like at a language level (so I/O doesn't need special treatment).
(there's a whole thing about "monad = IO" in laypeople discussion of Haskell which I think muddies this. There are loads of monads not about doing side effects, like list. But instead people think there's a link between monads and side effects, because we say "IO monad" instead of just "in IO" or something)
EDIT: it's v true that like.... side effects are side effects are side effects, so you can take that shortcut when talking about stuff. But if you want to get into the details about whether some expression is pure or not, you're brushing up against important semantics!
main = do
putStrLn "Hello, what's your name?"
name <- getLine
putStrLn $ "Hello " ++ name
And one in JavaScript: function main() {
let name = prompt('Hello, what is your name?');
alert('Hello, ' + name);
}
My claim is that either both have side effects or neither. In both cases the definition of a function does not in itself have side effects, and the function can be passed around and manipulated without being executed. But when the function is executed, it causes side effects.Haskell have the feature that the type system can statically verify if functions are pure or not. This is very cool, but it does not change the semantics or purity of a function, it just verifies it statically.
That means that you have already eliminated all the unnecessary side effects (in both cases), and there is no extra work that could be made pure (also in both cases).
Haskell gives you good tools to limit number of side effects to minimum necessary and verify that it is so.
JavaScript? It's free for all and people talk all the time how developer discipline leads to more maintainance codebases. Examples give for that discipline? (Almost) all are about more purity.
Edit: sorry I glossed over the last bit regarding a sub-language. The point is the whole language is considered (at least by many of its proponents) pure: monads + runtime + FFI are the gymnastics that allow one to perform IO in a pure language.
main = do
putStrLn "Hello, what's your name?"
name <- getLine
putStrLn $ "Hello " ++ name
is not pure in any meaningful sense. At least not any more pure than the similar code in any other language. function main() {
let name = prompt('Hello, what is your name?');
alert('Hello, ' + name);
}
This function can also be passed around, kept in lists etc. without executing it. So you can also say it is a specification of impure actions. It only has effect when executed by the runtime. So within JavaScript I guess it is 100% pure?The main point is: Within haskell we have purity, if you have Int -> Int it is referentially transparent, it can't do anything but take inputs and produce outputs.
If we have an expression like
let x = y + z y = 10 + z z = 3
these are just expressions that are reduced to a type and a value.
IO () is a type, a higher kinded type that satisfies properties the same way a list does. This type has meaning and the meaning is some "Side effectful action producing something". we can manipulate, map and combine this type and it just represents some action to be performed, which is pure as it just represents the actions. The value is the actions to perform.
A haskell program is an expression that reduces to the type of an action IO ().
So while yes both the IO monad and the js can represent the same effects, it isn't equivalent when we are looking at something that was never pure to begin with and drawing the similarities of what they represent.
(a, b) => a + b;
While this function is not pure: (msg) => console.log(msg)
However by your definition I guess the above function is actually also pure, since it can be passed around and manipulated without executing it?The cool thing about Haskell is that purity can be statically guaranteed by the type system and that unpure function are explicitly marked as such in their type signature.