2

EDIT: problem partially solved, skip to the bottom for update.

I'm writing a small language using haskell, and I've made a lot of progress, but I am having trouble implementing statements that use blocks, like "{ ... }". I've implemented support for If statements like so in my parser file:

stmt = skip +++ ifstmt +++ assignment +++ whilestmt

ifstmt = symbol "if" >>
         parens expr >>= \c ->
         stmt >>= \t ->
         symbol "else" >>
         stmt >>= \e ->
         return $ If c t e

whilestmt = symbol "while" >>
            parens expr >>= \c ->
        symbol "\n" >>
        symbol "{" >>
        stmt >>= \t ->
        symbol "}" >>
        return $ While c t

expr = composite +++ atomic

And in the Syntax file:

class PP a where 
  pp :: Int -> a -> String

instance PP Stmt where
  pp ind (If c t e) = indent ind ++ 
                      "if (" ++ show c ++ ") \n" ++ 
                      pp (ind + 2) t ++
                      indent ind ++ "else\n" ++
                      pp (ind + 2) e
  pp ind (While c t) = indent ind ++
                   "while (" ++ show c ++") \n" ++
                   "{" ++ pp (ind + 2) t ++ "}" ++
                   indent ind

Something is wrong with the while statement, and I don't understand what. The logic seems correct, but when I run the code I get the following error:

EDIT: Fixed the first problem based on the first reply, now it is not recognizing my while statment which I assume comes from this:
exec :: Env -> Stmt -> Env
exec env (If c t e) = 
    exec env ( if eval env c == BoolLit True then t else e )
exec env (While c t) =
    exec env ( if eval env c == BoolLit True then t )

The file being read from looks like this:

x = 1; c = 0;
if (x < 2) c = c + 1; else ;
-- SEPARATE FILES FOR EACH
x = 1; c = 1;
while (x < 10)
{
  c = c * x;
  x = x + 1;
}
c

I've tried to understand the error report but nothing I've tried solves the problem.

Nibirue
  • 411
  • 1
  • 15
  • 29

2 Answers2

4

>> and >>= bind tighter than $. Try using

return (While c t)

instead of

return $ While c t

And also, put parenthesis around the lambda expression on the right hand side of >>=.

Or just use do-notation:

whilestmt = do
    symbol "while"
    c <- parens expr
    symbol "\n"
    symbol "{"
    t <- stmt
    symbol "}"
    return $ While c t
Daniel Fischer
  • 181,706
  • 17
  • 308
  • 431
Joachim Breitner
  • 25,395
  • 6
  • 78
  • 139
0

The problem is that in Haskell, an if statement always has to have an else in addition to a then. Your implementation of exec for While specifies what to do when the condition is True, but says nothing about the behavior when the condition is False. In fact, your code only executes the body of the while loop once when the condition is True, but it should keep executing it (and threading the updates to the environment) until the condition becomes False. So, something like this:

exec env (While c t) = execWhile env c t

execWhile env c t | eval env c == BoolLit True = let env' = exec t in execWhile env' c t
                  | otherwise = env
pat
  • 12,587
  • 1
  • 23
  • 52
  • Oh, I just noticed that you duplicated the question, and already got an answer... – pat Oct 14 '12 at 22:26