Search code examples
parsinghaskellread-eval-print-loop

Should variables and strings be treated differently in constructing a language?


I'm currently working on a language and have come to an issue regarding variable declarations in that to check what value a variable is in the REPL, I must use quotation marks.

> x := 1
> "x"
1

The desired behaviour however would be the following:

> x := 1
> x
1

I have defined my ADT in the following way:

data S = Integer Integer | String String | Assign String S | Expr Add [S] 

I can parse everything correctly.

parseString :: Parser HVal
parseString = char '"' *> many1 (noneOf "\"") <* char '"' >>= (return . String)

parseAssign :: Parser HVal
parseAssign = do
         var <- many1 letter
         spaces
         string ":="
         spaces
         val <- try (parsersHVal)
         spaces
         return $ Assign var val

I think however that the problem is done to the evaluation functions.

evalHVal :: Env -> HVal -> IOThrowsError HVal
evalHVal env val@(Integer _)  = return $ val
evalHVal env val@(String  _)  = return $ val
evalHVal env (String  val)    = getVar env val >>= \var -> evalHVal env var

If I keep the first line that evaluates a string, the following occurs in the REPL and I receive a warning that the second line is redundant:

> x := 1
> "x"
'x'

If I keep the second line however I get the behaviour as described from the beginning.

In both cases, quotations around the variable have to be placed in order to evaluate it. I recongise though that I use many1 letter rather than parseString in the function parseAssign. I have tried changing this to parseString but I obtain the same behaviour.

What confuses me the most however is that since everything is read in as a string, then why doesn't many1 letter require quotations in parseAssign like how parseString requires? I tried changing parseString to the following (many1 letter >>= (return . String)) but it neither assigns nor allows for the use of strings like before.


Solution

  • Should variables and strings be treated differently in constructing a language?

    Yes

    data S = ...
    

    Should be:

    data S = ... | Var String
    

    What confuses me the most however is that since everything is read in as a string, then why doesn't many1 letter require quotations in parseAssign like how parseString requires?

    That should be obvious. See the definition:

    parseString = char '"' *>  ...
    

    The very first part of parseString clearly looks to parse char '"'.

    The definition of parseAssign does not look for ".

    I tried changing parseString to the following (many1 letter >>= (return . String)) but it neither assigns nor allows for the use of strings like before.

    Well " is not a letter so it shouldn't/wouldn't allow for a quotation mark. More, it wouldn't "assign", whatever that verb means, because it lacks the Assign constructor along with all the other critical parts of parseAssign.