OCaml函数参数模式匹配字符串

时间:2012-03-25 18:57:34

标签: ocaml

我尝试传入一个字符串来获取反向字符串。为什么我不能这样做:

let rec reverse x = 
  match x with
  | "" -> ""
  | e ^ s -> (reverse s) ^ e;;

编译器说它是语法错误。我不能用^来构造参数吗?

3 个答案:

答案 0 :(得分:18)

原因是字符串不像列表那样表示为数据类型。因此,虽然cons(::)是构造函数,但^ 不是。相反,字符串表示为较低级别类型而没有递归定义(如列表所示)。有一种方法可以将字符串作为字符列表进行匹配,使用来自SML的函数(可以在OCaml中编写),称为'explode'和'implode',它分别将字符串转换为字符列表,反之亦然。 Here's an example implementation of them.

答案 1 :(得分:2)

编写模式匹配表达式时,不能在模式中使用任意函数。您只能使用构造函数,它们看起来像未评估的函数。例如,函数“+”在整数上定义。所以表达式1+2被评估并给出3;评估函数“+”,因此无法在x+y上匹配。这是尝试在自然数上定义一个函数,检查数字是否为零:

 let f x =  match x with
  | 0 -> false
  | a+1 -> true
 ;;

这不行!出于同样的原因,您的字符串示例无法正常工作。函数“^”在字符串上计算,它不是构造函数。

仅当数字是未评估的运算符x+1和符号常量+的未评估符号表达式时,1上的匹配才有效。在OCAML中并非如此。整数直接通过机器号实现。

当您匹配变体类型时,您将匹配构造函数,这些构造函数是未评估的表达式。例如:

 # let f x = match x with
    | Some x -> x+1
    | None -> 0
 ;;
 val f : int option -> int = <fun>

这是有效的,因为'a option类型是由符号表达式构成的,例如Some x。这里,Some不是被评估的函数,而是给出了一些其他值,而是一个“构造函数”,您可以将其视为一个永不评估的函数。表达式Some 3未进一步评估;它仍然保持原样。只有这样的功能才能进行模式匹配。

列表也是由构造函数构建的符号化,未评估的表达式;构造函数是::x :: y :: []的结果是一个未评估的表达式,仅为了方便起见而由列表[x;y]表示。因此,您可以在列表上进行模式匹配。

答案 2 :(得分:2)

作为Kristopher Micinski explained,您无法像使用列表一样使用模式匹配来分解字符串。

但您可以使用explode将它们转换为列表。这是您使用reverse及其对应explode进行模式匹配的implode函数:

let rec reverse str =
  match explode str with
    [] -> ""
    | h::t -> reverse (implode t) ^ string_of_char h

像这样使用:

let () =
  let text = "Stack Overflow ♥ OCaml" in
  Printf.printf "Regular: %s\n" text;
  Printf.printf "Reversed: %s\n" (reverse text)

这表明它适用于单字节字符,但不适用于多字节字符。

以下是explodeimplode以及辅助方法:

let string_of_char c = String.make 1 c

(* Converts a string to a list of chars *)
let explode str =
  let rec explode_inner cur_index chars = 
    if cur_index < String.length str then
      let new_char = str.[cur_index] in
      explode_inner (cur_index + 1) (chars @ [new_char])
    else chars in
  explode_inner 0 []

(* Converts a list of chars to a string *)
let rec implode chars =
  match chars with
    [] -> ""
    | h::t ->  string_of_char h ^ (implode t)