OCaml function parameter pattern matching for strings

The reason for this is that strings are not represented as a datatype in the same way as lists are. Therefore, while cons (::) is a constructor, ^ is not. Instead, strings are represented as a lower level type without a recursive definition (as lists are). There is a way to match strings as a list of characters, using a function from SML (which you can write in OCaml) called 'explode' and 'implode' which --respectively -- take a string to a char list and vice versa. Here's an example implementation of them.


As Kristopher Micinski explained, you can't decompose strings using pattern matching as you do with lists.

But you can convert them to lists, using explode. Here's your reverse function with pattern matching using explode and its counterpart implode:

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

Use it like this:

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

Which shows that it works for single-byte characters but not for multi-byte ones.

And here are explode and implode along with a helper method:

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)

When you write a pattern matching expression, you cannot use arbitrary functions in your patterns. You can only use constructors, which look like unevaluated functions. For example, the function "+" is defined on integers. So the expression 1+2 is evaluated and gives 3; the function "+" is evaluated, so you cannot match on x+y. Here is an attempt to define a function on natural numbers that checks whether the number is zero:

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

This cannot work! For the same reason, your example with strings cannot work. The function "^" is evaluated on strings, it is not a constructor.

The matching on x+1 would work only if numbers were unevaluated symbolic expressions made out of the unevaluated operator + and a symbolic constant 1. This is not the case in OCAML. Integers are implemented directly through machine numbers.

When you match a variant type, you match on constructors, which are unevaluated expressions. For example:

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

This works because the 'a option type is made out of a symbolic expression, such as Some x. Here, Some is not a function that is evaluated and gives some other value, but rather a "constructor", which you can think of as a function that is never evaluated. The expression Some 3 is not evaluated any further; it remains as it is. It is only on such functions that you can pattern-match.

Lists are also symbolic, unevaluated expressions built out of constructors; the constructor is ::. The result of x :: y :: [] is an unevaluated expression, which is represented by the list [x;y] only for cosmetic convenience. For this reason, you can pattern-match on lists.

Tags:

Ocaml