Last statement in 'do' must be an expression error.

Hi. When trying to compilke this code: {...} 8.if (a == 0) && (b == 0) 9. then do 10. nr1 <- read (prompt "enter 1. number: ") 11. nr2 <- read (prompt "enter 2. number: ") 12. else do 13. let nr1 = a 14. nr2 = b {...} The compiler tells me thats there's an error on line 10: "The last statement in a 'do' construct mesy be an expression" Could you tell me how to change it so that the "declaration" of the first nr1 and nr2 is still in the "then" block.

On Aug 17, 2006, at 10:18 AM, Szymon Ząbkiewicz wrote:
Hi.
When trying to compilke this code:
{...} 8.if (a == 0) && (b == 0) 9. then do 10. nr1 <- read (prompt "enter 1. number: ") 11. nr2 <- read (prompt "enter 2. number: ") 12. else do 13. let nr1 = a 14. nr2 = b {...}
The compiler tells me thats there's an error on line 10: "The last statement in a 'do' construct mesy be an expression"
Could you tell me how to change it so that the "declaration" of the first nr1 and nr2 is still in the "then" block.
The problem is that variables defined in the branch of an if are local to the branch. If you want to use them outside you have to return them from the branch: do (nr1, nr2) <- if (a == 0) && (b == 0) then do nr1 <- read (prompt "enter 1. number: ") nr2 <- read (prompt "enter 2. number: ") return (nr1, nr2) else do let nr1 = a nr2 = b return (nr1, nr2) / Ulf

On Thu, Aug 17, 2006 at 10:18:25AM +0200, Szymon Z??bkiewicz wrote:
To: haskell-cafe@haskell.org From: Szymon Z??bkiewicz
Date: Thu, 17 Aug 2006 10:18:25 +0200 Subject: [Haskell-cafe] Last statement in 'do' must be an expression error. Hi.
When trying to compilke this code:
{...} 8.if (a == 0) && (b == 0) 9. then do 10. nr1 <- read (prompt "enter 1. number: ") 11. nr2 <- read (prompt "enter 2. number: ")
each do block needs to evaluate to some value when performed. if you have nothing to return, do something like "return ()". (note this only works if the type checker is happy with it. possibly you need to restructure parts of the code you didn't post, too.)
12. else do 13. let nr1 = a 14. nr2 = b {...}
The compiler tells me thats there's an error on line 10: "The last statement in a 'do' construct mesy be an expression"
Could you tell me how to change it so that the "declaration" of the first nr1 and nr2 is still in the "then" block.
what about this code (untested)? do nr1 <- if a == 0 then read (prompt ":") else return a nr2 <- if b == 0 then read (prompt ":") else return b ... hth, m.

Szymon Ząbkiewicz wrote:
Hi.
When trying to compilke this code:
{...} 8.if (a == 0) && (b == 0) 9. then do 10. nr1 <- read (prompt "enter 1. number: ") 11. nr2 <- read (prompt "enter 2. number: ")
The nr2 here is not passed to the rest of the do block started on line 9
12. else do 13. let nr1 = a 14. nr2 = b
The nr1 and nr2 in the else block have absolutely nothing to do with the nr1 and nr2 from the then block. The names are the same, but that does not make them the same as they could be totally different types.
{...}
The compiler tells me thats there's an error on line 10: "The last statement in a 'do' construct mesy be an expression"
Could you tell me how to change it so that the "declaration" of the first nr1 and nr2 is still in the "then" block.
The "x <- foo" syntax is not a declaration. Also, the type of "read" is String->a which is NOT a monad type, so I will fix that as well: One could do this: (nr1,nr2) <- if (a==0) && (b==0) then do a' <- liftM read (prompt "...") b' <- liftM read (prompt "...") return (a',b') else return (a,b) The ghc compiler is usually smart enough to remove the tuple (,) construction from the code.

Hello Szymon, Thursday, August 17, 2006, 12:18:25 PM, you wrote:
8.if (a == 0) && (b == 0) 9. then do 10. nr1 <- read (prompt "enter 1. number: ") 11. nr2 <- read (prompt "enter 2. number: ") 12. else do 13. let nr1 = a 14. nr2 = b {...}
1. as already said, your nr vars is local to the do blocks. you can't _assign_ to variables in Haskell, instead you should return _values_ that will become result of whole "if" expression: (nr1,nr2) <- if ... then do x <- .. y <- .. return (x,y) else do return (a,b) 2. as Chris said, "read" is a function (at least 'read' predefined in std Haskell library), while your 'prompt' should be I/O procedure. you can't call I/O procedures inside of functions, i.e. that is possible: function calls function I/O procedure calls function I/O procedure calls I/O procedure and that's impossible: function calls I/O procedure So you should assign result of procedure call to "variable" and then call function on this value: (nr1,nr2) <- if a==0 && b==0 then do x <- prompt "enter 1. number: " y <- prompt "enter 2. number: " return (read x, read y) else return (a,b) to be exact, x and y are not variables, but just bound identifiers like a and b. '<-' is special construct inside of 'do' block that binds to identifier value returned by I/O procedure call i've written tutorial on Haskell IO monad. you can try to read it, but it's more appropriate for intermediate Haskellers who has a good understanding of pure facilities of the language. but nevertheless try it - http://haskell.org/haskellwiki/IO_inside . i will be interesting to hear your opinion and depending on it will become more or less skeptical about suggesting it to Haskell newcomers fighting with mysterious IO monad :D in general, i suggest to learn pure foundations of Haskell such as lazy evaluation and higher-order functions. after that, learning IO monad using my tutorial will be as easy as saying "cheese" :) -- Best regards, Bulat mailto:Bulat.Ziganshin@gmail.com

Szymon Z??bkiewicz wrote:
The compiler tells me thats there's an error on line 10: "The last statement in a 'do' construct must be an expression"
I think, you have reached the point where treating do-notation as magic won't help you. Remember,
do nr1 <- read (prompt "enter 1. number: ") nr2 <- read (prompt "enter 2. number: ")
is syntactic sugar for
read (prompt "enter 1. number: ") >>= \nr1 -> read (prompt "enter 2. number: ") >>= \nr2 ->
and it obvious that something is missing after the last arrow. That's the expression the compiler is complaining about. After the translation, it is also completely clear, that there is no "variable" which is ever "declared" and could be "assigned". On a side note, using "trap values" like the special 0 is an ugly style inherited from C. You might want to get used to explicit representations for missing values. Compare this:
read_new :: Maybe (Int, Int) -> IO (Int, Int) read_new (Just ab) = return ab read_new Nothing = do n1 <- read_prompt "enter 1. number: " n2 <- read_prompt "enter 2. number: " return (n1, n2) where read_prompt p = prompt p >>= readIO
Also note the 'read_prompt' function; I'm pretty sure you got the types of 'prompt' and 'read' messed up, too. So in anticipation of your next question: 'read'ing the 'prompt' action is not the same as 'read'ing the result of the 'prompt' action. Only the latter makes sense. Udo. -- "Enthusiasm is contagious, and so is boredom." -- Paul Graham
participants (6)
-
Bulat Ziganshin
-
Chris Kuklewicz
-
Matthias Fischmann
-
Szymon Ząbkiewicz
-
Udo Stenzel
-
Ulf Norell