Let clause nested in if clause nested in do clause - haskell

I'm currently working my way through Learn You a Haskell for Great Good, and I'm trying to modify one of the code snippets in chapter nine, "Input and Output" to handle errors correctly:
main = do
(command:args) <- getArgs
let result = lookup command dispatch
if result == Nothing
then
errorExit
else
let (Just action) = result
action args
where
dispatch :: [(String, [String] -> IO ())]
is an association list
and
errorExit :: IO ()
is some function that prints an error message.
Compiling this with GHC gives the error message
todo.hs:20:13: parse error in let binding: missing required 'in'
which (to my understanding), seems to be saying that the "let" here doesn't realise it's in a "do" block.
Adding "do" on lines five and seven (after "then" and "else" respectively), changes the error message to
todo.hs:20:13:
The last statement in a 'do' block must be an expression
let (Just action) = result
todo.hs:21:5: Not in scope: `action'.
and now, whilst I agree with the first error message, I also have that one of my variables has jumped out of scope? I've double checked my alignment, and nothing seems to be out of place.
What is the appropriate way to assign a varaible within an if clause that is within a do block?

My suggestion is to not use if in the first place, use case. By using case you get to test the value and bind the result to a variable all in one go. Like this:
main = do
(command:args) <- getArgs
case lookup command dispatch of
Nothing -> errorExit
Just action -> action args
For a more in-depth discussion on why we should prefer case over if see boolean blindness.

#svenningsson suggested the right fix. The reason your original fails is because let clauses can only appear at the top level of a do block - they're simple syntactic sugar that doesn't look into inner expressions:
do let x = 1
y
desugars to the let expression
let x = 1 in y
Alas, in a do block, an expression clause like if ... then ... else ... has no way to declare variables in the rest of the do block at all.
There are at least two possible ways to get around this.
Absorb the remainder of the do block into the expression:
main = do
(command:args) <- getArgs
let result = lookup command dispatch
if result == Nothing
then
errorExit
else do
let (Just action) = result
action args
(This is essentially the method #svenningsson uses in his better case version too.)
This can however get a bit awkward if the remainder of the do expression needs to be duplicated into more than one branch.
("Secret" trick: GHC (unlike standard Haskell) doesn't actually require a final, inner do block to be indented more than the outer one, which can help if the amount of indentation starts getting annoying.)
Pull the variable declaration outside the expression:
main = do
(command:args) <- getArgs
let result = lookup command dispatch
action <- if result == Nothing
then
errorExit
else do
let (Just action') = result
return action'
action args
Here that requires making up a new variable name, since the pattern in the let clause isn't just a simple variable.
Finally, action was always out of scope in the last line of your code, but GHC works in several stages, and if it aborts in the parsing stage, it won't check for scope errors. (For some reason it does the The last statement in a 'do' block must be an expression check at a later stage than parsing.)
Addendum: After I understood what #Sibi meant, I see that result == Nothing isn't going to work, so you cannot use if ... then ... else ... with that even with the above workarounds.

You are getting an error because you are trying to compare values of function type. When you perform the check if result == Nothing, it tries to check the equality of Nothing with the value of result which is a type of Maybe ([String] -> IO ()).
So, if you want it to properly typecheck, you have to define Eq instances for -> and that wouldn't make any sense as you are trying to compare two functions for equality.
You can also use fmap to write your code:
main = do
(command:args) <- getArgs
let result = lookup command dispatch
print $ fmap (const args) result

Related

How to accumulate changes without renaming variable?

I have a list of Strings, errors. I do some checks and if any fail, I append a message to errors. Something like this:
let errors = []
let errors' = errors ++ if (check1 fails) then ["check1 failed"] else []
let errors'' = errors' ++ if (check2 fails) then ["check2 failed"] else []
Surely there is a more idiomatic way to accumulate changes to errors without making a new variable every time. Do I need to break out Data.IORef for mutable variables? Seems like overkill.
If I simply remove the apostrophes, the compiler returns an error because it gets caught in an infinite loop.
You could group the conditions and messages together
checksTodo = [(check1 fails, "check1 failed"), (check2 fails, "check2 failed")]
errors = map snd (filter fst checksTodo)
If you are comfortable using the list comprehension syntax, you could instead write it in a more readable fashion:
errors = [ msg | (cond, msg) <- checksTodo, cond ]
If I simply remove the apostrophes, the compiler returns an error because it gets caught in an infinite loop.
This is happening because let bindings in Haskell (unlike most languages) are recursive by default. Which means that if you say
let errors = errors ++ if (check1 fails) then ["check1 failed"] else []
the compiler will treat it as a recursive definition. When you try to evaluate errors at runtime, you go into an infinite loop as you need errors to compute errors.
Another alternative:
let errors =
[ "check1 failed" | check1 fails ] ++
[ "check2 failed" | check2 fails ] ++
...
What theindigamer said, plus, the idiomatic way to do error checking is usually having your checker return an Either: if something goes wrong, produce a Left with the error message, otherwise a Right with the result.
Since, in this case, your checks aren't producing an actual result, you can make the result the unit type (); thus, you can convert your checks to generate Either like this:
check1Either = if check1 fails then Left "check1 failed" else Right ()
And then, just run the checks and filter the elements with a Left using the lefts function in Data.Either:
import Data.Either
errors = lefts [check1Either, check2Either]
(You might ask, if there isn't going to be a result to fill Right with, why not use Maybe? You can, and filter errors with catMaybes from Data.Maybe; it's just that Nothing is usually interpreted to mean that the computation failed, and Just usually means success - the opposite of what happens here - whereas, idiomatically speaking Left is usually interpreted as an error)

strange execution order requirement on two monadic actions in Hint (Language.Haskell.Interpreter)

In the code at the bottom, two monadic actions (loadModules and setImportsQ) in Hint (Language.Haskell.Interpreter) can only be executed in one order but not the other, as shown in a minimal example below. In particular, loadModules must go first, or else the following exception will be generated when executing the interpreter.
*** Exception: compile error: WontCompile [GhcError {errMsg = "Not in scope: type
constructor or class `Int'"}]
This behavior seems to have been introduced in Hint 0.4.1.0. I must have missed something obvious..
My first questions is Hint specific: why must loadModules be called before setImportsQ?
My second question is more general: it seems that these two monadic actions do NOT feed input into each other, also the to-be-loaded module is empty, why is the order or execution important at all? This almost reminds me of the imperative world, where you not only have to worry about the input/output, but also the order of certain side effects.
The code is below. Note that MyModule.hs is an empty .hs file.
module Main where
import Language.Haskell.Interpreter
import Control.Monad
custom=["MyModule"] --mymodule.hs is just an empty .hs source file in the same folder
context=[("Data.Int",Nothing)]
main = do
x <- interp ("1") (as ::Int)
return ()
interp e as_type = do
interpreterResult <- runInterpreter $ do
loadModules custom --this line must go first
setImportsQ context --this line must go second
interpret e as_type
f <- case interpreterResult of
Left e -> error $ "compile error: " ++ show e
Right result -> return result
return f

Implement imperative return statement in interpreter

I'm trying to implement simple imperative language in haskell.
Generally speaking my program is a list of statements (like arithmetic expression, if/then, block statement). My evaluator has simple state: stack of lexical scopes. Lexical scope is just map of variable name to value. I push lexical scope every time as control flow enters function or block and pop as control flow leaves function or block.
But I've encountered a problem while trying to implement evaluation of return statement.
What I'm trying to do is to make a special case for return statement in main evaluating function(sources here):
evalStatements :: [Statement] -> Eval MaybeValue
-- nothing to evaluate
evalStatements [] = return Nothing
-- current statement is 'return expr',
-- evaluate expr and skip the rest of statements
evalStatements (ret#(ReturnStatement _expr):_stmts) =
leaveLexEnv -- leave current lexical scope
evalStatement ret >>= return
-- this is last statement in function, eval it and leave lexical scope
evalStatements [stmt] = do
res <- evalStatement stmt
leaveLexEnv -- leave current lexical scope
return res
evalStatements (st:stmts) =
evalStatement st >> evalStatements stmts >>= return
evalStatement :: Statement -> MaybeValue
evalStatement (ExprStatemet expr) = ...
evalStatement (IfThenStatement expr stmt) = ...
But special case in evalStatements function looks ugly for me. And this approach doesn't work with BlockStatement, because return statement can be inside this block statement.
Another problem is restoring stack of lexical scopes, when return statement is located inside multiple nested block statements.
I think I can solve this problem with storing some additional state in my evaluator, but this approach looks not very good. Something tells me that continuations can help me here. But I don't understand continuations very well yet.
What is best way to solve this problem? I need just an idea, general concept.
Thanks.
Continuations can work here, but they're way overkill. In fact, continuations are almost always overkill for solving any specific problem.
The simplest solution is to put the necessary logic into your Eval type. If you make Eval contain a constructor for "this computation returned early with this value", and then make your definitions of (>>) and (>>=) respect that, everything will work out automatically.

Haskell: Need Enlightenment with Calculator program

I have an assignment which is to create a calculator program in Haskell. For example, users will be able to use the calculator by command lines like:
>var cola =5; //define a random variable
>cola*2+1;
(print 11)
>var pepsi = 10
>coca > pepsi;
(print false)
>def coke(x,y) = x+y; //define a random function
>coke(cola,pepsi);
(print 15)
//and actually it's more complicated than above
I have no clue how to program this in Haskell. All I can think of right now is to read the command line as a String, parse it into an array of tokens. Maybe go through the array, detect keywords such "var", "def" then call functions var, def which store variables/functions in a List or something like that. But then how do I store data so that I can use them later in my computation?
Also am I on the right track because I am actually very confused what to do next? :(
*In addition, I am not allowed to use Parsec!*
It looks like you have two distinct kinds of input: declarations (creating new variables and functions) and expressions (calculating things).
You should first define some data structures so you can work out what sort of things you are going to be dealing with. Something like:
data Command = Define Definition | Calculate Expression | Quit
type Name = String
data Definition = DefVar Name Expression | DefFunc Name [Name] Expression
-- ^ alternatively, implement variables as zero-argument functions
-- and merge these cases
data Expression = Var Name | Add Expression Expression | -- ... other stuff
type Environment = [Definition]
To start off with, just parse (tokenise and then parse the tokens, perhaps) the stuff into a Command, and then decide what to do with it.
Expressions are comparatively easy. You assume you already have all the definitions you need (an Environment) and then just look up any variables or do additions or whatever.
Definitions are a bit trickier. Once you've decided what new definition to make, you need to add it to the environment. How exactly you do this depends on how exactly you iterate through the lines, but you'll need to pass the new environment back from the interpreter to the thing which fetches the next line and runs the interpreter on it. Something like:
main :: IO ()
main = mainLoop emptyEnv
where
emptyEnv = []
mainLoop :: Environment -> IO ()
mainLoop env = do
str <- getLine
case parseCommnad str of
Nothing -> do
putStrLn "parse failed!"
mainLoop env
Just Quit -> do
return ()
Just (Define d) -> do
mainLoop (d : env)
Just (Calculate e) -> do
putStrLn (calc env e)
mainLoop env
-- the real meat:
parseCommand :: String -> Maybe Command
calc :: Environment -> Expression -> String -- or Integer or some other appropriate type
calc will need to look stuff up in the environment you create as you go along, so you'll probably also need a function for finding which Definition corresponds to a given Name (or complaining that there isn't one).
Some other decisions you should make:
What do I do when someone tries to redefine a variable?
What if I used one of those variables in the definition of a function? Do I evaluate a function definition when it is created or when it is used?
These questions may affect the design of the above program, but I'll leave it up to you to work out how.
First, you can learn a lot from this tutorial for haskell programming
You need to write your function in another doc with .hs
And you can load the file from you compiler and use all the function you create
For example
plus :: Int -> Int -- that mean the function just work with a number of type int and return Int
plus x y = x + y -- they receive x and y and do the operation

Nested `do` blocks in Haskell

I'm trying to write a function in Haskell which checks for some things and then recurses based on some minimal user input. In order to do that I think I have to use do blocks.
cip :: [Argument] -> [Argument] -> Bool -> Bool -> IO()
cip (a:args) pargs burden gameover = do
let nasko = a:pargs
putStrLn (getPremise a)
let newgraph = Carneades.mkArgGraph nasko
let newcaes = (CAES (newgraph,audience2,assStandarts))
let answer = (acceptable (mkProp (getPremise a)) newcaes )
print answer
if(answer==True)
then (cip args nasko burden gameover)
else do
print "One of the arguments is not proved. Here are the premises that need proving"
print (propsForFixing newcaes a)
print "Let's see what you have for the first Propositon"
--add an if to check if no applicable arguments.
print (argumentScanHelp (head (propsForFixing newcaes a)) args)
print "\n Would you like me to apply the firt one? Y/N"
choice <- getLine
if(choice=="Y") then do print "applying the argument"
let applicabee = head (argumentScanHelp (head (propsForFixing newcaes a)) args)
print "Argument targeted"
let newargs = delete applicabee args
let newpargs = applicabee:nasko
print "Argument applied sucsessfuly. Recusing again"
(cip newargs newpargs burden gameover)
return()
It hurts my eyes just by looking at it, but that's do blocks for you.
Everything up to the third do block is okay. But then on this line:
if(choice=="Y") then do print "applying the argument"
let applicabee = head (argumentScanHelp (head (propsForFixing newcaes a)) args)
The complier starts crying:
Main.hs:209:73: parse error on input `let'
Tried a all kinds of different indentations but I can't seem to get it to work.
I don't want to use separate functions, because that means I'll have to pass a lot of arguments around constantly.
Can anyone help me get it right? Also an explanation of what exactly the specifications for nested do block are would be greatly appreciated.
The cause of the error I believe is the misuse of the if expression. You use it as if it were an if statement that exists in most imperative languages. Simply put there must always be an else.
However, in do blocks it makes sense to "not have an else", something like an if statement without an else. Luckily the Control.Monad module will provide you with a function for exactly that:
import Control.Monad (when)
(...)
when (choice=="Y") $ do print "applying the argument"
let applicabee = ...
You seem to already use nested do blocks in the correct way which is good, which basically is that you must indent properly.
PS. Also make sure your last return () is indented like the rest of your code! DS.

Resources