Here is a simplified version of the code I’m working on.
main :: IO ()
main = do
args <- getArgs
if null args
then putStr "> " ; userInput <- getLine
else userInput <- readFile $ head args
let conclusion = userInput
This won’t work without do notation, the variable won’t pass to conclusion below when I do use it, and the putStr, which I’m trying to use to create a kind of prompt, just makes it mad.
Is there something that I’m forgetting to add somewhere?
There are a few problems here. First, you need to include
doafterthenandelse:ifin do notation is the same asifeverywhere else; you have to put an expression afterthenandelse, not statements, and you needdoto turn a bunch of statements into an expression. This still isn’t quite valid, though; the last statement in adoblock must be an expression, but you have a bind here. After all, every statement has to have a result value, but a bind has none.The second problem is, as you’ve observed, that this introduces a new scope, and so you can’t access variables you bind from outside. This makes sense if you think about it; after all, you could bind the variable on one side and not the other. The solution is to simply move the bind outside the
if:So, the action whose result we bind to
userInputis still computed depending on the result ofnull args, but we bind the variable outside the conditional.Note that I didn’t add a
doto theelsebranch this time; it’s not required, since there’s only a single expression there. (It’s still valid, but it’s unidiomatic to usedowhen it’s not necessary.)This code still won’t work unless you put something after the
let conclusion = userInputline (since, like I said,doblocks must end with an expression), but presumably you already have code there.As an additional note, you should avoid using functions like
headandtail;headis a partial function (not defined for every argument —head []will produce an error), and those are generally considered unidiomatic. You should use pattern-matching instead, like this:This is just like the pattern-matching used when defining a function, but for a single value rather than any number of arguments.