Haskell - saving content of HTTP request in selected file
Right from the top I notice you could benefit from some factoring.
prompt :: String -&gt; IO String
prompt str = do
    putStr str
    hFlush stdout
    getLine

Then getURL is prompt &quot;URL: &quot; (and maybe doesn't even need to exist separately!) and confirmOverideOrGetNewPath and getOutputFilepath both lose two lines at the top. You'll notice that I also wrote this function with do-notation, it's a stylistic preference but I just don't like to run monads into one line like that, not sure if I have a great reason why. I guess it just feels right to make imperative-y monadic code look like an imperative language would.
The diversion through shouldOverride in confirmOverideOrGetNewPath is unnecessary, just put your expression in the case-statement.
case decision == &quot;y&quot; of
  True -&gt; ...

But then I'd also skip the check for equality entirely and just pattern match on the returned string.
case decision of
    &quot;y&quot; -&gt; return filepath
    &quot;n&quot; -&gt; getOutputFilepath
    _   -&gt; do
      putStrLn &quot;Unrecognized input&quot;
      confirmOverrideOrGetNewPath filepath

I changed the logic to make the behavior more elucidating. If a user actually enters &quot;n&quot;, it's not really necessary to tell them to provide a new path since getOutputFilepath will prompt them for a new one immediately. The user presumably expects that, given their input. If they type something other than &quot;y&quot; or &quot;n&quot;, instead of requiring them to input a new path, just check again if they're cool with the override.
In getOutputFilepath all I'd note is that file_exists should be camel cased for consistency.
Over the rest of your program, the only thing I'd switch up would be the whole logic around response codes. In performGetRequest I'd just change the return type to be ResponseCode instead of Int, and push your display logic into printHttpStatusCode (which should probably be printResponseCode). Since ResponseCode is just a type alias for tuples, you can also pattern match in the function call (i.e. in your original version responseCodeToInt (x, y, z) = ... instead of the let). And then it also probably makes more sense to have a pure showResponseCode and leave printing up to the caller.
showResponseCode :: ResponseCode -&gt; String
showResponseCode (i, j, k) = concatMap show [i, j, k]

Then I'd just carry the changes through to main and reorder things for clarity and truth in logic.
main = do
    ...
    (content, statusCode) &lt;- performGetRequest url
    putStrLn $ &quot;Response status: &quot; ++ showResponseCode statusCode
    writeFile filepath content
    putStrLn &quot;Content saved&quot;