添加到OCaml中的字符串映射

添加到OCaml中的字符串映射,ocaml,Ocaml,我一直在试图弄清楚,我认为这是一项非常简单的任务,即从函数中向OCaml中的字符串映射添加条目。有关内容如下: module StringMap = Map.Make (String);; let m = StringMap.empty;; let rec count ke = match ke with |[] -> [] |hd::tl -> begin let m = StringMap.add hd 1 m; [hd] @ count tl end;; 我一直收到神秘

我一直在试图弄清楚,我认为这是一项非常简单的任务,即从函数中向OCaml中的字符串映射添加条目。有关内容如下:

module StringMap = Map.Make (String);;
let m = StringMap.empty;;

let rec count ke = match ke with
 |[] -> []
 |hd::tl -> begin let m = StringMap.add hd 1 m; [hd] @ count tl end;;

我一直收到神秘的“语法错误”消息,但我还没有找到解决方案,即使在将代码剥离到基本上什么都没有的情况下。我可以用一个命令添加到字符串映射,但是如果我尝试从函数中运行
let m=StringMap.add hd 1 m
,它将无法运行。我相信这是一个简单的问题,但是有人能帮忙吗?谢谢。

您的代码似乎有一些问题。但首先,这里有一个关于如何做您正试图做的事情的示例:

module StringMap = Map.Make (String)

let rec count m ke =
    match ke with
    | [] -> m
    | hd :: tl -> count (StringMap.add hd 1 m) tl

let m = count StringMap.empty ["foo"; "bar"; "baz"]
对原始代码的一些评论:

  • 双分号用于告诉REPL循环您希望它使用您的代码。如果不使用它,你应该避免它们
  • 单个分号用于分隔命令式表达式,例如在赋值之后。这里有一个let表达式,它的语法是“let-in”,因此在后面使用分号是错误的。(“不带“in”的let a=…”是顶级构造,不能在本地使用)
  • StringMap(以及ocaml中的大多数其他结构)是功能性的,而不是强制性的。不能对第一行中声明的“m”进行变异。您必须构建结构,最后在循环结束时返回完全构建的结构

您的困惑源于您误解了
let
构造的含义。它不修改对象:它不是赋值语句。(
let
构造为值命名。
let
构造的语法是
name
=
value
进入
表达式
这会导致名称引用表达式中的值。在将名称绑定到该值之前,会计算一次该值。名称的作用域是表达式,因此不能使用它引用表达式之外的值(另一方面,该值在垃圾回收之前一直存在)

顶级
let
构造类似于表达式中的构造,但在
表达式部分中没有
。名称的范围是程序的其余部分(就好像在
部分中有一个
,包含下面的所有内容,至少在进入模块之前是如此)

您正试图修改顶级
m
,但这不是
来做的工作:您需要一个赋值。Ocaml有一个赋值运算符,
:=
,它赋值给现有引用。引用是一个可以修改的对象。这在Ocaml中不是自动的:与C、Java和Lisp等语言不同,Ocaml不使用单一语言功能为值命名和创建可修改的存储。
ref
函数创建一个可修改的对象;您可以使用
:=
分配它,并使用
操作符获取其值:

let r_m = ref StringMap.empty;; (*the type of r_m is 'a StringMap.t ref*)
let rec count ke = match ke with
  | [] -> []
  | hd::tl -> r_m := StringMap.add hd 1 !r_m; [hd] @ count tl;;

但是,这不是很好的Ocaml样式。Ocaml支持这种命令式样式,但您应该避免它,因为命令式编程比函数式编程更容易出错。函数式样式是在您想要修改对象时创建一个新值。请注意,
Map
模块创建的映射旨在支持t此样式:
add
返回与旧对象共存的新对象(即,它是一个持久数据结构)。切换到函数样式需要您更改
count
函数的接口;这是您无论如何都想做的事情,通过将映射作为参数传递,可以在不同的映射上使用
count
函数。我建议您使用良好Ocaml样式的示例代码。

回答得好(虽然我认为这是值得的),但我不建议不要使用双分号。它们不是必需的,但也没有坏处。这里有一些关于;;的含义的讨论;根据我自己的经验,双分号通常有助于确定语法/范围错误。。。