mercredi 27 janvier 2021

Evaluation of custom If representation terminates if a guard to a statement is false

If-statements in my language should be in the following form:

if ((4 div 2) = 2)-> print(1)
[] ((4 div 2) > 1)-> print(2)
[] ((4 div 2) > 2)-> print(3)
fi

The output to this should be one and two printed to the console however if I were to switch the positions of the middle and last statement, only the first statement would be evaluated and then the program would terminate. It seems that the behaviour that is exhibited is that the evaluation of the if-statements is predicated upon the value of the guard such that if 1..n guards are true and if the n+1 guard is false, then the "falseness" breaks the evaluation.

I think I narrowed down the issue to how an if-statement is individually evaluated.

evalStatement_ env (If cond expr) = evalVal env cond >>= \x -> case x of
                                                                     HBool False -> return ()
                                                                     HBool True  -> traverse_ (evalStatement_ env) expr

If a statement whose guard (cond) is evaluated to false then the path that's taken is return (). It seems that if this is taken then the program stops because when all guards are true then the statements can be executed. But in my evaluation of basic datatypes, I also have return () :

evalStatement_ env (Eval val) = do
    result <- evalVal env val
    return ()

This function takes a HVal and evaluates it and returns () but given the behaviour of what is occurring with if-statements, this has left me really confused because in this case, the program doesn't stop.

The other possible issue could be down to my representation of if-statements.

data HVal
  = HInteger Integer
  | HBool    Bool
  | HString  String
  | HList    [HVal]
  | Length   HVal
  | Arith    HVal Op HVal
  | Assign   String HVal
    deriving (Eq, Read)


data HStatement
  =  Eval   HVal
  |  Print  HVal
  |  Do     HVal [HStatement]
  |  Selection [HStatement]
  |  If     HVal [HStatement]
  |  Skip   String
    deriving (Eq, Read)

An if-statement is built up from a single HVal, the guard/cond and a list of HStatements which carry out what is to be evaluated if the guard is true. Selection however is what actually handles the work. It is supposed to be representative of multiple if-statements hence the list.

parseIf :: Parser HStatement
parseIf = do
        string "if" <|> string "[]"
        spaces
        string "("
        cond  <- parseVals
        string ")->"
        spaces
        expr  <- many1 (try (parseSkip) <|> try (parseDo <* spaces) <|> try (parsePrint) <|> try (parseEvalHVal))
        return $ If cond expr


parseSelection :: Parser HStatement
parseSelection = liftM Selection $ (many1 parseIf)

So when I go to evaluate Selection, what's supposed to occur is that the evalStatement_ env function is applied to each entry within the list which in turn allows for the entirety of the list to be evaluated but clearly that's not the case! When I went to print out what was actually "in' the Selection in the following program, only the first statement was found within the block:

if ((4 div 2) = 2)-> print(1)
[] ((4 div 2) < 1)-> print(2)
[] ((4 div 2) > 1)-> print(3)
fi

./Main if.oli
[Print (1 )
[]

]
1

This leads me to believe it's either a parsing error or there's something to do with return () but I genuinely don't know how to proceed.

----- EVAULATION FUNCTIONS -----
evalStatement_ :: Env -> HStatement -> IOThrowsError ()
evalStatement_ env (Do cond expr) = evalVal env cond >>= \x -> case x of
                                                                 HBool False -> return ()
                                                                 HBool True  -> do
                                                                         traverse_ (evalStatement_ env) expr
                                                                         evalStatement_ env (Do cond expr)

evalStatement_ env (Skip skip) = return ()
evalStatement_ env (Print (HString val)) = getVar env val >>= \x -> liftIO $ putStrLn $ show x
evalStatement_ env (Print val) = evalVal env val >>= \x -> liftIO $ putStrLn $ show x
evalStatement_ env (Eval val) = do
    result <- evalVal env val
    return ()
evalStatement_ env (If cond expr) = evalVal env cond >>= \x -> case x of
                                                                     HBool False -> return ()
                                                                     HBool True  -> traverse_ (evalStatement_ env) expr
evalStatement_ env (Selection selection) = do
        traverse_ (evalStatement_ env) selection

Aucun commentaire:

Enregistrer un commentaire