This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 10 years ago.
The error must be so tiny in these few lines that I will not get it myselft.
Here is my code:
askName = do
putStr "Type your name: "
name <- getLine
return name
sayHelloTo name = do
when (null name) (name <- askName)
Apparently it gives an error:
1 of 1] Compiling Main ( test.hs, interpreted )
test.hs:9:30: parse error on input `<-'
Failed, modules loaded: none.
Any suggestion?
Edit 1.
Same if I write:
sayHelloTo name = do
when (null name) (name2 <- askName)
The name2 <- syntax is part of do-notation and can only be used inside a do block. It is also not a variable assignment - under the hood it is just creating a callback function that has name2 as a parameter
That is, the following code:
do
name2 <- monadicOp
...things...
desugars into
monadicOp >>= (\name2 -> ...things... )
I hope this helps make it clear that you don't assign things or mutate them in Haskell.
anyway, to solve your particular problem, whay you could do is just use if-then-else (something that is actually equivalent to the ?: ternary oerator) and return the appropriate value. For example, the following function uses recursion to ask for a name again and again until it is happy with the result
getNonEmptyName :: IO String
getNonEmptyName = do
name <- getName
if null name --note: indenting if statements in do blocks is tricky
then getNonEmptyName
else (return name)
or, without the do notation sugar:
getNonEmptyName = getName >>= (\name -> if (null name) then getNonEmptyName else (return name) )
This might be a bit moe different the what you are used to, but I guess you should be able to clear thing sup after you get how this is working. Basically getNonEmptyName is of type IO String, meaning it is an IO actioin IO action that yields a String when it is run. The if-then-else part is supposed to evaluate to an IO String value as well, since its value will be the return value of getNonEmptyName. This all works all right since in the first we do a recursive call to getNonEmptyName (and that gives an IP String value as desired) and in the else branch we promote a regular string value (name) to an IO String using the return function.
It's not entirely clear what sayHelloTo is supposed to do or return -- it's certainly not going to modify name -- but at a guess, you might mean something like
sayHelloTo :: String -> IO String
sayHelloTo name
| null name = askName
| otherwise = return name
Related
This question already has an answer here:
How to use variable from do block assignment line in a where clause?
(1 answer)
Closed 2 years ago.
I'm trying to use the variable defined in the outer scope within an action defined in do block using where:
module Main where
main :: IO ()
main = do
outerVar <- return "a"
doSomething
where
doSomething :: IO String
doSomething = putStrLn ("outerVar: " ++ outerVar)
Given this snippet, I'm trying to understand why does the compiler return the following error:
error: Variable not in scope: outerVar :: [Char]
|
9 | doSomething = putStrLn ("outerVar: " ++ outerVar)
|
Based on my understanding - doSomething function should create some kind of a "closure" to contain the value of outerVar (which I've just found out is called a free variable), but that doesn't happen.
I've spent quite a lot of time trying to figure out why exactly does this error happen. I'm quite embarassed as, even for me as a Haskell newbie, it seems almost like a basic concept that should be obvious but it isn't - hopefully I'm wrong. I couldn't find any answers when searching for "where in do block scope", "where closure" or similar keywords. This page that compares let and where doesn't mention my case, the closest example I've found is the first bit of code from here where the "Lambda lifting" topic is covered. They're able to use n variable from outer scope within the function defined in where, but it's not in a do block as my case is.
So my question is - why exactly is outerVar variable not in scope of doSomething?
do blocks are just syntactic sugar for chaining monadic values using >>= and lambda functions. Your block is first translated by the compiler into:
return "a" >>= \outerVar -> doSomething
where doSomething =...
It should be obvious now that outerVar is not in scope outside the lambda to which it is an argument.
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
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.
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
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.