我在OCaml中有这个基本问题,现在已经困扰了我很久了。我有模式匹配,比较用户的输入并打印出连接的字符串。这工作正常,但我现在需要将此连接字符串添加到模式匹配中的集合。每次我尝试这样做时都会收到错误:
This expression has type SS.t = Set.Make(String).t
but an expression was expected of type string
我对OCaml很陌生,这已经花了这么多天,而我却无法弄明白。模式匹配的代码如下:
type t = Zero | Pproc of string | Procdef of t * t
module SS = Set.Make(String)
let set2= SS.empty
let concattoset s =
List.fold_right SS.add [s] set2
let rec poc p = match p with
| Zero -> concattoset "0"
| Pproc x -> concattoset x
| Procdef (p1, p2) -> concattoset((poc p1)^"("^(poc p2)^")")
我遇到的错误是:
Procdef (p1, p2) -> concattoset((poc p1)^"("^(poc p2)^")");;
^^^^^^^^
Error: This expression has type SS.t = Set.Make(String).t
but an expression was expected of type string
答案 0 :(得分:3)
我编辑了您的问题,但一旦经过同行评审,它就可以使用了。然而,让我们回答你的问题(顺便说一下,不要说“谢谢!”并尝试举例说明有助于重现你的错误。)
因此,您的代码如下所示:
type t = Zero | Pproc of string | Procdef of t * t
module SS = Set.Make(String)
let set2= SS.empty
let concattoset s =
List.fold_right SS.add [s] set2
let rec poc p = match p with
| Zero -> concattoset "0"
| Pproc x -> concattoset x
| Procdef (p1, p2) -> concattoset((poc p1)^"("^(poc p2)^")")
你的错误是:
Procdef (p1, p2) -> concattoset((poc p1)^"("^(poc p2)^")");;
^^^^^^^^
Error: This expression has type SS.t = Set.Make(String).t
but an expression was expected of type string
首先,一个集合是不可变的,因此SS.add
将返回一个新集合,而不是unit
。
根据此,concattoset
的类型为SS.elt -> SS.t
,则poc
的返回类型与concattoset "0")
的类型相同。
那是因为当编译器尝试键入一个匹配模式的函数时,它会根据模式匹配的每个案例返回的内容推断出类型:
let rec poc p = match p with
| Zero -> concattoset "0"
| ...
此处p
的类型为t
,因为它与Zero
匹配且concattoset
的类型为string -> SS.t
,因此concattoset "0"
属于SS.t
类型poc
然后t (*the type of p*) -> SS.t (the type returned by concattoset "0"
的类型为concattoset ((poc p1) ^ poc p2))
。
当您致电poc p1
时,concattoset : string -> SS.t) but has the type
应该是一个字符串((the return type of
SS.t type t = Zero | Pproc of string | Procdef of t * t
module SS = Set.Make(String)
let concattoset ?s1 ?sep1 ?sep2 s2 set =
let str = Printf.sprintf "%s%s%s%s"
(match s1 with None -> "" | Some s -> s)
(match sep1 with None -> "" | Some s -> s)
s2
(match sep2 with None -> "" | Some s -> s)
in
SS.add str set;;
let rec poc p set = match p with
| Zero -> concattoset "0" set
| Pproc x -> concattoset x set
| Procdef (p1, p2) -> concattoset ~s1:(poc p1) ~sep1:"(" ~sep2:")" (poc p2) set
poc p1`),这就是编译器告诉您的内容。< / p>
您可以编写的代码(丑陋)是:
concattoset
但这样做有点尴尬,如果你的类型有多个构造函数,很快就会很难写出一个好的let rec pp fmt = function
| Zero -> Format.fprintf fmt "0"
| Pproc x -> Format.fprintf fmt "%s" x
| Procdef (p1, p2) -> Format.fprintf fmt "%a(%a)" pp p1 pp p2
| Timer(t,chan, var, p1, p2) -> Format.fprintf fmt "timer%s(%s(%s).%a,%a)" t chan var pp p1 pp p2;;
let concattoset s set = SS.add s set;;
let poc p set = concattoset (Format.asprintf "%a" pp p) set;;
。
我要做的是以下(为更复杂的构造函数添加Timer):
pp
因此,concattoset
采用格式化程序(可以看作输出缓冲区),在构造函数中打印必要的递归调用。 SS.add
就像poc
一样简单,t
采用pp
类型的参数和一个集合,并使用格式化程序作为字符串调用concattoset
并给出此%a
的新字符串,这正是您想要的。
关于pp
:
Format.asprintf "%a" pp p
期待2个参数可能看起来有点奇怪,但我打电话时只给出一个,例如pp
。好吧,实际上,我没有将p
应用于Format.asprintf "%a" (pp p)
,在这里,我正在给打印机提供2个参数,如文档中所述:
a:用户定义的打印机。拿两个参数并应用第一个参数 outchan(当前输出通道)和第二个参数。该 因此,第一个参数必须具有类型out_channel - &gt; 'b - &gt;单位和 第二个'b。函数产生的输出插入到 当前点的fprintf输出。
这就是编译器不接受编写^(AY)0*([1-9].*)
的原因。
答案 1 :(得分:1)
我无法重现您的错误。当我尝试使用类型的简化版本的类似示例时,没有错误。
# let set2 = SS.empty;;
val set2 : SS.t = <abstr>
# let concattoset s = List.fold_right SS.add [s] set2;;
val concattoset : SS.elt -> SS.t = <fun>
# let proc p = match p with
| None -> concattoset "0"
| Some s -> concattoset s;;
val proc : SS.elt option -> SS.t = <fun>
# SS.elements (proc (Some "def"));;
- : SS.elt list = ["def"]
然而,在我看来,你希望能够将一个集合视为一个可变容器。 OCaml中的一个集是不可变的。如果你想构建更大更大的集合,你需要将一个输入集传递给你的函数,并让函数添加到该集合(而不是空集),并返回结果。
这是一个会话,可以说明集合是不可变的意义:
# module SS = Set.Make(String);;
module SS : sig ... end
# let s = SS.empty;;
val s : SS.t = <abstr>
# SS.elements s;;
- : SS.elt list = []
# SS.add "abc" s;;
- : SS.t = <abstr>
# SS.elements s;;
- : SS.elt list = []
表达式SS.add "abc" s
返回包含字符串"abc"
的新集合。它不会更改s
,这是不可变的。
在OCaml中,当您谈到将字符串添加到集合时,这意味着您正在创建包含字符串的 new 集合。前一组(不可变)不会改变。
这是一个函数,它将两个给定的字符串添加到一个集合中,并返回新的集合:
let add2 set s1 s2 =
SS.add s1 (SS.add s2 set)
set
参数是输入集。该函数的结果是一个新的,更大的集合。输入集在过程中不会更改(它是不可变的)。