Genuinely curious, not that familiar with Haskell, just thought you could use something like parameter binding or similar to construct functions like that.
I'm used to Boost.Bind and similar, so was thinking a scenario where you bind the database connection parameter and pass the resulting function to something else.
As the sibling pointed out though, I now get that the result would be "tainted" so to speak.
In this case you can think of a monad a bit like a computational context. If one is not present, you simply cannot[^1] instruct a Haskell program to perform those operations in a type safe way even if you give it a valid database connection identifier.
[1] Well, you can, but if you do you're explicitly taking away all the safeguards that Haskell introduces, and it would never pass code review.
Int -> Int -> IO Bool
otherwise the type checker won't let you perform any side-effecting operations(btw Haskell's `IO Bool` would be spelled `IO<Bool>` in C++/Java syntax)
edit: So at work, just about every value depends directly or indirectly on stuff that comes from files or from the database. So would they all have to be wrapped by IO?
The core logic of a program often doesn't need to care deeply about state or system resources. Pure functional programming is about writing as much as you can in this "functional core", and then lifting the assembled pieces of pipeline into the "imperative shell" (such as the IO monad).
Its argument is a function of type `String -> String` and it returns an `IO ()`, i.e. an i/o action with a trivial result. That action will call the given function on contents of stdin, and writes its result to stdout. Or, equivalently, we can think of `interact f` as transforming a pure string-processing function `f` into a stdio CLI.
Note that laziness (specifically "lazy IO") causes stdin to be read 'on demand', giving us a streaming computation without any extra work. Here's an example implementation of 'wc':
module Main where
import System.IO
main :: IO ()
main = interact count
count :: String -> String
count input = show (length (unwords input))
Bonus: if we want to show off, we could implement 'count' using function composition like this: count = show . length . unwords[handwavy analogy alert]
people often call it "side-effects" as a shorthand. in reality an expression being of type `IO Foo` mostly just tells the compiler that order of execution matters (which isn't the case with pure functions):
do print "a"
print "b"
-- obviously not the same as
do print "b"
print "a"
and also that it can't eliminate common expressions: do a <- readBytes file 100
b <- readBytes file 100
doStuff a b
-- obviously not the same as
do x <- readBytes file 100
doStuff x x
it's a way of enforcing ordering in a lazy language where evaluation order isn't really defined.