0

非常接近让它工作,但在使用 OCaml 的 StringMap 时遇到问题。本质上,我正在制作一个计算器,它从 ocamllex 接收词汇流......所以这里应该用逗号分隔我们的表达式,而等号意味着我们将为变量赋值。

我意识到,在分配变量时,我无法查找它们,因为我在函数的 Var 案例中添加的未找到密钥的行中出现 (Fatal error: exception Not_found)。我不知道将 StringMap.empty 放在哪里或如何使其在此函数中可见......我想知道为什么它找不到我在 equals 情况下添加的内容?

这是我的代码。

open Ast

module StringMap = Map.Make(String)

let varMap = StringMap.empty

let rec parser = function

  Lit(x) -> x
| Binop(e1, op, e2) -> (
      let v1 = parser e1 and v2 = parser e2 in
      match op with
            Add -> v1 + v2
            | Sub -> v1 - v2
            | Mul -> v1 * v2
            | Div -> v1 / v2
      )
| Var(v) -> StringMap.find v varMap
| Statements(e1, e2) ->   ignore(parser e1); parser e2
| Equals(v, e1) ->  StringMap.add v e1 varMap; parser e1

let _ =
  let LexingBuffer = Lexing.from_channel stdin in
  let expression = Parser.expression Scanner.token LexingBuffer in
  let result = parser expression in
  print_endline (string_of_int result)
4

2 回答 2

3

Map是不可变的数据结构。任何更改地图的函数都将返回一个新的修改实例,而前一个实例保持不变。因此,这个表达式

StringMap.add v e1 varMap; parser e1

只会丢弃新地图,并返回递归调用返回的任何内容parser。如果要使用Map,则必须保留新实例。您可以通过制作varMap一个更新的参考单元来做到这一点:

let varMap = ref StringMap.empty

...

varMap := StringMap.add v1 !varMap

或者通过添加一个函数参数parser并将其传递:

let rec parser varMap = function

...

parser (StringMap.add v e1 varMap) e1

另一种选择是使用Hashtbl代替,它可变的并且非常适用于字符串。

于 2019-03-10T18:55:30.733 回答
1

地图是不可变的。线

StringMap.add v e1 varMap; parser e1

因此正在计算更新的地图,然后立即将其丢弃。换句话说,地图varMap总是空的。

为了避免丢弃环境映射,您应该parser通过将其添加为函数的参数来在函数本身中跟踪它——您可以将其重命名为eval

  let rec eval env = function
  | ...
于 2019-03-10T18:50:20.277 回答