Print a List in OCaml
Asked Answered
O

11

44

I want to do something as simple as this:

Print a list.

let a = [1;2;3;4;5]

How can I print this list to Standard Output?

Odawa answered 3/2, 2012 at 20:16 Comment(2)
What did you try? Did you know about the %a format specification (for user defined printing) of Printf.printf ?Caxton
I just began learning OCaml. I tried the %d format specification. Actually i wasn't aware of the ';' that allows specifying more than one statement - like in the answer by ackar.Odawa
U
40

You can do this with a simple recursion :

let rec print_list = function 
[] -> ()
| e::l -> print_int e ; print_string " " ; print_list l

The head of the list is printed, then you do a recursive call on the tail of the list.

Untidy answered 3/2, 2012 at 20:21 Comment(3)
what is the significance of the empty parentheses on the second line?Hellbent
@Hellbent () is the object of type unit, which I believe is the standard thing that's usually returned by a function to be executed only for side-effects. Other printing functions such as print_int also have return type unit. If you execute the let above, you'll see that print_list will have return type unit. Something else could in principle be returned, e.g. 42, or "All done printing!", in which case the return type would be int or string, respectively.Hanghangar
since print_int is deprecated List.iter/List.map with printf is a better option.Trample
C
70

You should become familiar with the List.iter and List.map functions. They are essential for programming in OCaml. If you also get comfortable with the Printf module, you can then write:

open Printf
let a = [1;2;3;4;5]
let () = List.iter (printf "%d ") a

I open Printf in most of my code because I use the functions in it so often. Without that you would have to write Printf.printf in the last line. Also, if you're working in the toploop, don't forget to end the above statements with double semi-colons.

Chlorobenzene answered 3/2, 2012 at 22:21 Comment(2)
If you use the List module from Core (e.g. you are following Real World Ocaml) you need to do: List.iter ~f:(printf "%d ") aProprietor
FYI, this answer refers to Stdlib.Printf (and stdlib.List), so if you're using Core or Base, and have open Core or open Base at the top of the file, you will need to open Stdlib.Printf instead of just open Printf. Base's Printf doesn't provide printf.Pierides
U
40

You can do this with a simple recursion :

let rec print_list = function 
[] -> ()
| e::l -> print_int e ; print_string " " ; print_list l

The head of the list is printed, then you do a recursive call on the tail of the list.

Untidy answered 3/2, 2012 at 20:21 Comment(3)
what is the significance of the empty parentheses on the second line?Hellbent
@Hellbent () is the object of type unit, which I believe is the standard thing that's usually returned by a function to be executed only for side-effects. Other printing functions such as print_int also have return type unit. If you execute the let above, you'll see that print_list will have return type unit. Something else could in principle be returned, e.g. 42, or "All done printing!", in which case the return type would be int or string, respectively.Hanghangar
since print_int is deprecated List.iter/List.map with printf is a better option.Trample
T
35
print_string (String.concat " " (List.map string_of_int list))
Tryst answered 20/2, 2012 at 8:24 Comment(1)
If you're a parenthesis hater: print_string @@ String.concat " " @@ List.map string_of_int listOvercharge
S
8

If the question is about finding the quickiest way to implement this, for example when debugging, then we could say that:

  • extended standard libraries (e.g. batteries) typically have some additional functions:

    List.print
      ~first:"[" ~sep:";" ~last:"]" (fun c x -> Printf.fprintf c "%d" x) stdout a
    
  • this tiny syntax extension that I wrote some time ago allows you to write:

    <:print<[$!i <- a${$d:i$}{;}]>>
    
  • automatic generation is not immediately available (because of the lack of run-time type information in OCaml data representation) but can be achieved using either code generation from the types, or run-time types.
Sodomite answered 20/2, 2012 at 13:13 Comment(0)
S
8

I'm very late answering, but here's another way:

let print_list f lst =
  let rec print_elements = function
    | [] -> ()
    | h::t -> f h; print_string ";"; print_elements t
  in
  print_string "[";
  print_elements lst;
  print_string "]";;

To print an int list, we could write:

print_list print_int [3;6;78;5;2;34;7];;

However if we were going to do this a lot, it would save time to specialize the function using partial application:

let print_int_list = print_list print_int;;

Which we can now use like so:

print_int_list [3;6;78;5;2;34;7];;

What if we wanted to do something pretty complex, like printing an int list list? With this function, it's easy:

(* Option 1 *)
print_list (print_list print_int) [[3;6;78];[];[5];[2;34;7]];;

(* Option 2 *)
let print_int_list_list = print_list (print_list print_int);;
print_int_list_list [[3;6;78];[];[5];[2;34;7]];;

(* Option 3 *)
let print_int_list_list = print_list print_int_list;;
print_int_list_list [[3;6;78];[];[5];[2;34;7]];;

Printing an (int * string) list (i.e. a list of pairs of ints and strings):

(* Option 1 *)
print_list (fun (a, b) -> print_string "("; print_int a; print_string ", "; print_string b; print_string ")") [(1, "one"); (2, "two"); (3, "three")];;

(* Option 2 *)
let print_pair f g (a, b) =
  print_string "(";
  f a;
  print_string ", ";
  g b;
  print_string ")";;
print_list (print_pair print_int print_string) [(1, "one"); (2, "two"); (3, "three")];;

(* Option 3 *)
let print_pair f g (a, b) =
  print_string "(";
  f a;
  print_string ", ";
  g b;
  print_string ")";;
let print_int_string_pair = print_pair print_int print_string;;
print_list print_int_string_pair [(1, "one"); (2, "two"); (3, "three")];;

(* Option 4 *)
let print_pair f g (a, b) =
  print_string "(";
  f a;
  print_string ", ";
  g b;
  print_string ")";;
let print_int_string_pair = print_pair print_int print_string;;
let print_int_string_pair_list = print_list print_int_string_pair;;
print_int_string_pair_list [(1, "one"); (2, "two"); (3, "three")];;
Streptothricin answered 29/10, 2013 at 0:45 Comment(1)
Interesting, the only 'drawback' is there's always an additional ; in the list. For example [[4;2;];[2;];]Elasticity
M
4

I would do this in the following way:

let a = [1;2;3;4;5];;
List.iter print_int a;;
Moy answered 12/2, 2017 at 5:26 Comment(4)
should be List.iter a print_int;;Halloween
@Halloween ocaml.org/learn/tutorials/camlp4_3.10/foreach_tutorial.html says it should be List.iter print_int a;;Moy
Oh okay - I'm using OCaml Core which has switched the syntax here: ocaml.janestreet.com/ocaml-core/111.28.00/doc/core/#Core_list The type for List.iter in Core is 'a t -> f:('a -> unit) -> unitHalloween
And to get rid of the "labels were omitted" warning you would do: List.iter a ~f:print_int;;Halloween
C
3

Actually, you can decouple printing a list and turning a list into a string. The main advantage for doing this is that you can use this method to show lists in logs, export them to CSVs...

I often use a listHelper module, with the following :

(** Generic method to print the elements of a list *)
let string_of_list input_list string_of_element sep =
  let add a b = a^sep^(string_of_element b) in
  match input_list with
  | [] -> ""
  | h::t -> List.fold_left add (string_of_element h) t

So, if I wanted to output a list of floats to a csv file, I could just use the following :

let float_list_to_csv_row input_list = string_of_list input_list string_of_float "," 
Communal answered 14/5, 2018 at 9:18 Comment(1)
Might be more idiomatic if the list is the last argument the function takes.Overcharge
T
2

Just a solution with %a :

open Printf
let print_l outx l = 
     List.map string_of_int  l
  |> String.concat ";"
  |> fprintf outx "%s"

Test :

# printf "[%a]\n" print_l [1;2;3] ;;
[1;2;3]
- : unit = ()
# printf "[%a]\n" print_l [];;
[]
- : unit = ()
Translation answered 14/2, 2017 at 3:49 Comment(0)
R
1
let print_list l =
  let rec aux acc =
    match acc with
     | [] -> ()
     | x :: tl ->
       Printf.fprintf stdout "%i"; aux tl
   in aux l

Or

let sprintf_list l =
  let acc = ref "{" in
  List.iteri (fun i x ->
    acc := !acc ^
      if i <> 0
      then Printf.sprintf "; %i" x
      else Printf.sprintf "%i" x
  ) l;
  !acc ^ "}"

let print_list l =
  let output = sprintf_list l in
  Printf.fprintf stdout "%s\n" output
Rude answered 3/7, 2015 at 7:59 Comment(0)
C
0

I added this line of code to the recursive function that I saw on this thread. Because, it was printing the element ";" for example, even for the last element. This is a very useful function because you can print almost any type of list (even list of list) with ease.

| hd::[] -> f hd

let print_list f l =
  let rec print_elements = function
    | [] -> ()
    | hd::[] -> f hd 
    | hd::tl -> f hd; print_string ";"; print_elements tl
  in print_string "["; print_elements l; print_string "]";;
Cusco answered 4/7, 2023 at 19:34 Comment(0)
O
0

Utilizing first class modules and the Format module, we can now make a very flexible list_to_string (or call it string_of_list if you prefer) without writing a lot of code.

# let list_to_string 
      (type t) 
      (module M : Stringable with type t = t) 
      ?(sep = "; ") 
      (lst : t list) =
    let rec aux ppf = function
      | [] -> Format.fprintf ppf ""
      | [x] -> Format.fprintf ppf "%s" (M.to_string x)
      | x::xs -> Format.fprintf ppf "%s%s" (M.to_string x) sep; aux ppf xs
    in
    Format.asprintf "[%a]" aux lst;;
val list_to_string :
  (module Stringable with type t = 't) -> ?sep:string -> 't list -> string =
  <fun>
# module StringRep = struct
    type t = string
    let to_string s = Format.sprintf {|"%s"|} s
end;;
module StringRep : sig type t = string val to_string : t -> t end
# print_endline 
  @@ list_to_string (module StringRep) ~sep: ", " 
  @@ List.map string_of_int [1; 2; 3; 4; 5];;
["1", "2", "3", "4", "5"]
- : unit = ()
# list_to_string (module Int) [1; 2; 3; 4; 5];;
- : string = "[1; 2; 3; 4; 5]"

It's also possible to modify this slightly to generalize it and make printing not require building an entire string first before printing it.

# let list_pp
      (type t)
      (module M : Stringable with type t = t)
      ?(sep="; ")
      ()
      ppf
      (lst : t list) =
    let rec aux ppf = function
      | [] -> ()
      | [x] -> Format.fprintf ppf "%s" (M.to_string x)
      | x::xs -> Format.fprintf ppf "%s%s" (M.to_string x) sep; aux ppf xs
    in
    Format.fprintf ppf "[%a]" aux lst;;
val list_pp :
  (module Stringable with type t = 't) ->
  ?sep:string -> unit -> Format.formatter -> 't list -> unit = <fun>

And then call:

# Format.printf "%a\n" (list_pp (module Int) ()) [1; 2; 3; 4];;
[1; 2; 3; 4]
- : unit = ()
Overcharge answered 26/11, 2023 at 18:14 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.