23

I want to write a function that taking a string and return a list of char. Here is a function, but I think it is not do what I want ( I want to take a string and return a list of characters).

let rec string_to_char_list s =
    match s with
      | "" -> []
      | n -> string_to_char_list n
Quyen
  • 1,363
  • 1
  • 11
  • 21
  • 1
    On the plus side, this will work for an empty string! You need to handle non-empty strings a little better. Since OCaml doesn't let you destructure a string with pattern matching, a function like this is probably going to use an index (an integer) to get at the characters in the string. – Jeffrey Scofield Apr 09 '12 at 03:58
  • 3
    `| n -> string_to_char_list n` that's an infinite loop for you. Never recurse with the same parameter you got in! – Ptival Apr 09 '12 at 06:49

7 Answers7

31

Aside, but very important:

Your code is obviously wrong because you have a recursive call for which all the parameters are the exact same one you got in. It is going to induce an infinite sequence of calls with the same values in, thus looping forever (a stack overflow won't happen in tail-rec position).


The code that does what you want would be:

let explode s =
  let rec exp i l =
    if i < 0 then l else exp (i - 1) (s.[i] :: l) in
  exp (String.length s - 1) []

Source: http://caml.inria.fr/pub/old_caml_site/FAQ/FAQ_EXPERT-eng.html#strings


Alternatively, you can choose to use a library: batteries String.to_list or extlib String.explode

smac89
  • 39,374
  • 15
  • 132
  • 179
Ptival
  • 9,167
  • 36
  • 53
28

Try this:

let explode s = List.init (String.length s) (String.get s)
smac89
  • 39,374
  • 15
  • 132
  • 179
6

Nice and simple:

let rec list_car ch = 
  match ch with
  | "" -> []
  | ch -> String.get ch 0 :: list_car (String.sub ch 1 (String.length ch - 1));;
Chris
  • 26,361
  • 5
  • 21
  • 42
WADIE SCAMS
  • 61
  • 1
  • 1
5

As of OCaml 4.07 (released 2018), this can be straightforwardly accomplished with sequences.

let string_to_char_list s =
  s |> String.to_seq |> List.of_seq

It may help to see an implementation of creating a sequence for a string. In the standard library, this is done by way of the bytes type, but we can implement a simple function to do the same directly with a string.

let string_to_seq s =
  let rec aux i () =
    if i = String.length s then Seq.Nil
    else Seq.Cons (s.[i], aux @@ i + 1))
  in
  aux 0

Or using exceptions:

let string_to_seq s =
  let rec aux i () =
    match String.get s i with
    | ch -> Seq.Cons (ch, aux @@ i + 1)
    | exception Invalid_argument _ -> Seq.Nil
  in
  aux 0
Chris
  • 26,361
  • 5
  • 21
  • 42
3

How about something like this:

let string_to_list str =
  let rec loop i limit =
    if i = limit then []
    else (String.get str i) :: (loop (i + 1) limit)
  in
  loop 0 (String.length str);;

let list_to_string s =
  let rec loop s n =
    match s with
      [] -> String.make n '?'
    | car :: cdr ->
       let result = loop cdr (n + 1) in
       String.set result n car;
       result
  in
  loop s 0;;
Paweł Obrok
  • 22,568
  • 8
  • 74
  • 70
Mayer Goldberg
  • 1,378
  • 11
  • 23
1

Here is an Iterative version to get a char list from a string:

let string_to_list s = 
  let l = ref [] in
  for i = 0 to String.length s - 1 do
    l := (!l) @ [s.[i]]
  done;
  !l;;
Chris
  • 26,361
  • 5
  • 21
  • 42
  • `@` in a loop or a recursive function call tends to be a bad idea for efficiency. Suggest you build up your list in reverse: `l := s[.[i] :: !l`, and then return `List.rev !l`. – Chris Feb 11 '23 at 21:10
1

My code, suitable for modern OCaml:

let charlist_of_string s =
  let rec trav l i =
    if i = l then [] else s.[i]::trav l (i+1)
  in
  trav (String.length s) 0;;

let rec string_of_charlist l =
  match l with
    [] -> "" 
  | h::t -> String.make 1 h ^ string_of_charlist t;;
Chris
  • 26,361
  • 5
  • 21
  • 42