String 连接OCaml中的字符串

String 连接OCaml中的字符串,string,recursion,concatenation,ocaml,String,Recursion,Concatenation,Ocaml,我正在编写一个递归OCaml函数,该函数将字符串连接到由分隔符连接的字符串列表中,而不在最后一项上放置分隔符,但我遇到了一些问题。我知道有一个string.concat函数,但我不想使用它来了解OCaml如何在后台执行这些操作。以下是我到目前为止的情况: ` ` 我使用模式匹配来匹配字符串列表l,并涵盖三种情况:如果字符串列表为空,则案例1不返回任何内容;如果列表不包含尾部,则案例2只返回头部。tailthree执行连接,同时在join函数上递归,以连接列表中的其他项,中间使用字符串分隔符。然而

我正在编写一个递归OCaml函数,该函数将字符串连接到由分隔符连接的字符串列表中,而不在最后一项上放置分隔符,但我遇到了一些问题。我知道有一个string.concat函数,但我不想使用它来了解OCaml如何在后台执行这些操作。以下是我到目前为止的情况:

`

`


我使用模式匹配来匹配字符串列表l,并涵盖三种情况:如果字符串列表为空,则案例1不返回任何内容;如果列表不包含尾部,则案例2只返回头部。tailthree执行连接,同时在join函数上递归,以连接列表中的其他项,中间使用字符串分隔符。然而,我不确定如何实现这一点,同时在尾部递归并尊重OCaml对每个语句求值为表达式的需求。这在C或Java中是一个很小的问题,但无法解决这个问题,我们非常感谢任何帮助或指针,因为它的价值,我不明白当列表头是一个空字符串时,为什么要采取不同的行为

以下是内置字符串串联函数在这种情况下的作用:

# String.concat "," [""; "yes"];;
- : string = ",yes"
在我看来,这很合理,这与非“列表头”的行为相同

假设您确实希望在head为“”时执行一些不同的操作,那么您的代码不会针对这种情况执行任何递归。因此,整个输出将只是一个分隔符


如果您继续编写
else
部分,同时使用
^
操作符和递归调用
join
,您应该会发现,在OCaml中,代码与在C或Java中一样简单。

不管它值多少钱,我不明白当列表头是空字符串时,您为什么要采取不同的行为

以下是内置字符串串联函数在这种情况下的作用:

# String.concat "," [""; "yes"];;
- : string = ",yes"
在我看来,这很合理,这与非“列表头”的行为相同

假设您确实希望在head为“”时执行一些不同的操作,那么您的代码不会针对这种情况执行任何递归。因此,整个输出将只是一个分隔符


如果您继续编写
else
部分,使用
^
操作符和递归调用
join
,您会发现在OCaml中代码与在C或Java中一样简单。

简单的
join
很简单:

let rec join separator = function
  | [] -> ""
  | [str] -> str
  | ""::strs -> join separator strs
  | str::strs -> str ^ separator ^ join separator strs
这避免了伪逗号,这似乎是您正在尝试的。请注意,这不是
List.concat
的行为

虽然对于刚接触OCaml的人来说这是一个合理的编程练习,但这种版本的
join
是不可接受的:它在字符串长度的总和上确实起到了二次作用。线性时间实现可能使用
缓冲区

let join separator = function
  | [] -> ""
  | [str] -> str
  | str::strs ->
    let buf = Buffer.create 0 in
    Buffer.add_string buf str;
    List.iter (function
        | "" -> ()
        | s ->
          Buffer.add_string buf separator;
          Buffer.add_string buf s)
      strs;
    Buffer.contents buf

这更难看,但具有可接受的时间复杂性。

简单的
连接非常简单:

let rec join separator = function
  | [] -> ""
  | [str] -> str
  | ""::strs -> join separator strs
  | str::strs -> str ^ separator ^ join separator strs
这避免了伪逗号,这似乎是您正在尝试的。请注意,这不是
List.concat
的行为

虽然对于刚接触OCaml的人来说这是一个合理的编程练习,但这种版本的
join
是不可接受的:它在字符串长度的总和上确实起到了二次作用。线性时间实现可能使用
缓冲区

let join separator = function
  | [] -> ""
  | [str] -> str
  | str::strs ->
    let buf = Buffer.create 0 in
    Buffer.add_string buf str;
    List.iter (function
        | "" -> ()
        | s ->
          Buffer.add_string buf separator;
          Buffer.add_string buf s)
      strs;
    Buffer.contents buf

它更难看,但具有可接受的时间复杂度。

但如何在同一else块中进行递归调用并执行串联操作而不引发OCaml类型错误?您尝试了什么?像这样的递归调用
连接分隔符tl
是一个合法的调用,它返回一个string类型的值(根据递归假设)。我真的明白了为什么这种递归调用会起作用,假设join包含两个参数。如果显示不工作的代码并解释其失败原因,您可能会得到更有用的答案。但是,如何在同一else块中进行递归调用并执行串联操作而不引发OCaml类型错误?您尝试了什么?像这样的递归调用
连接分隔符tl
是一个合法的调用,它返回一个string类型的值(根据递归假设)。考虑到连接包含两个参数,我实际上明白了这种递归调用为什么会起作用。如果您显示不起作用的代码并解释它是如何失败的,您可能会得到更有用的答案。