Haskell 快乐工具赋值给变量

Haskell Happy implement assign to variable

我正在尝试用 x = 4 和 pritn x 实现一些语言,使用 haskell 快乐的构造 到目前为止,我已经定义了这样的语法

 terms 
    : term                   { [] }
    | term terms             {  :  }

 term 
    : var '=' int             { Assign   }
    | print var               { Print  }

当我 运行 它超过

x = 4
print x
y = 5
print y

我明白了

[Assign "x" 4, Print "x", Assign "y" 5, Print "y"]

现在想具体实现,但是不知道怎么实现"assign"

虽然我不擅长 haskell,但从快乐的文档中我看到了 "let" 实现并得到了一些环境 p 在

中通过和评估的想法
Exp   : let var '=' Exp in Exp  { \p ->  ((, p):p) }
  | Exp1                    {  }

Exp1  : Exp1 '+' Term           { \p ->  p +  p }
  | Exp1 '-' Term           { \p ->  p -  p }
  | Term                    {  }

Term  : Term '*' Factor         { \p ->  p *  p }
  | Term '/' Factor         { \p ->  p `div`  p }
  | Factor                  {  }

Factor            
  : int                     { \p ->  }
  | var                     { \p -> case lookup  p of
                                    Nothing -> error "no var"
                    Just i  -> i }
  | '(' Exp ')'             {  }

我想 "assign" 实现必须对这个环境做些什么,但我找不到任何例子。我如何实施分配和打印,或者我在哪里可以找到它的信息或示例?

您已经非常熟悉解析器了。但是你想要构建的是一个 interpreter 用于你的小表达式语言,与解析逻辑分开。解析器将只为程序生成 AST,然后我们将单独对其进行评估。

代码实际上很小,但它被分成几个模块,所以我把它放在这个要点中:https://gist.github.com/sdiehl/c2dd1880e0ec6b65a120

我猜你的 AST 看起来像这样:

data Expr
  = Var String
  | Num Int
  | Print Expr
  | Assign String Int
  deriving (Eq,Show)

解析器看起来不错,但我认为您需要添加一个 var 产生式,这样像 print xprint 1 这样的表达式在语法中都可以是格式正确的。

%token
    int   { TokenNum $$ }
    var   { TokenSym $$ }
    print { TokenPrint }
    '='   { TokenEq }

%%

terms 
    : term                   { [] }
    | term terms             {  :  }

term 
   : var                     { Var  }
   | var '=' int             { Assign   }
   | print term              { Print  }

对于解释器,我们将使用 StateT + IO monad 来保存分配的变量并为我们程序中的每个 Print 函数调用 Haskell 的 print 函数。状态 monad 将保存变量与值的关联列表。 Assign 将简单地向列表添加一个新引用,而 Var 引用将在状态上使用 lookup 函数。

data Value
  = VInt Int
  | VUnit

instance Show Value where
  show (VInt x) = show x

type Eval = StateT Env IO
type Env = [(String, Value)]

eval1 :: Expr -> Eval Value
eval1 expr = case expr of
  Num a -> return (VInt a)
  Var a -> do
    env <- get
    case lookup a env of
      Just val -> return val
      Nothing -> error "Not in scope"
  Print a -> do
    a' <- eval1 a
    liftIO $ print a'
    return VUnit
  Assign ref val -> do
    modify $ \s -> (ref, VInt val) : s
    return VUnit

eval :: [Expr] -> IO ()
eval xs = evalStateT (mapM_ eval1 xs) []

仅此而已。