scanf not accepting first arg - ocaml

The following code runs with no errors:
let f x y =
print_int (max x y);
print_char ' ';
print_int (x + y) in
for i = 1 to Scanf.scanf "%d" (fun x -> x) do
Scanf.scanf "\n%d %d" f;
print_newline ();
done;
But when I declare a variable fmt to hold the format "\n%d %d" and pass it to scanf,I get an error,here is the new code:
let f x y =
print_int (max x y);
print_char ' ';
print_int (x + y) in
let fmt = "\n%d %d" in (* added *)
for i = 1 to Scanf.scanf "%d" (fun x -> x) do
Scanf.scanf fmt f; (* edited *)
print_newline ();
done;
I get this error:
File "prog.ml", line 7, characters 16-19:
Error: This expression has type string but an expression was expected of type
('a, Scanf.Scanning.in_channel, 'b, 'c -> 'd, 'a -> 'e, 'e) format6
Why does it work differently?is there any difference between the two codes?

The handling of printf/scanf formats in OCaml uses some compiler magic that treats a string constant as a format in the proper context. The problem is that you no longer have a string constant.
You can pre-convert a string constant to a format using the format_of_string function.
Change your let fmt = line to this:
let fmt = format_of_string "\n%d %d" in
This makes your code work for me.

As strange as it may seem, this is actually a value-added feature: scanning functions are type-checked at compile time, and in order to do this the compiler has to be able to clearly see the format string at the call site and make sure that no shenanigans are going on with it. Such shenanigans could lead to undesirable behaviour, as in the following example:
let fmt = "%d" in
let fmt' = fmt ^ (if input_type = "int" then " %d" else " %f") in
(* input_type is defined somewhere else in the program *)
(* the format string could now be either "%d %d" or "%d %f" *)
let a,b = Scanf.scanf fmt' (fun a b -> a,b)
(* the compiler cannot infer a type for `b` *)

Related

how to read two values in one entry in ocaml?

I have to get two integers, separated by a space, in two different variables, in just one input.
I've done let (c, d) = Scanf.scanf " %d %d" (fun a b -> (a, b)) but I get this error : This expression has type 'a * 'b but an expression was expected of type 'c -> 'd -> 'e
How can I do it?
Thanks!
Your code works and does not raise any error
let (c, d) = Scanf.scanf " %d %d" (fun a b -> (a, b))
Since this code reads from stdin, you might have written
let (c, d) = Scanf.scanf " %d %d" (fun a b -> (a, b))
1 2;;
in a toplevel which will result in the error that you are seeing: the parser reads the extract above as
Scanf.scanf " %d %d" (fun a b -> (a, b)) 1 2
and complains that Scanf.scanf " %d %d" (fun a b -> (a, b)) is a tuple that cannot be applied to 1 and 2.

How to log all elements of a list in Ocaml before returning the list?

I would like to log (print for now) all the elements in results before reducing it for return. Is there a way to achieve that?
let calculate ~size_of_experiment:s ~number_of_buckets:n =
let results = run_experiments s n in
List.iter (fun x -> print_endline x) results;
List.fold_left (fun x y -> x + (snd y)) 0 results
The code above does not compile:
Error: This expression has type (int * int) list
but an expression was expected of type string list
Type int * int is not compatible with type string
Your only problem seems to be that elements of the list are of type (int * int) and you are treating them as strings.
let string_of_int_pair (a, b) = Printf.sprintf "(%d, %d)" a b
let calculate ~size_of_experiment:s ~number_of_buckets:n =
let results = run_experiments s n in
List.iter (fun x -> print_endline (string_of_int_pair x)) results;
List.fold_left (fun x y -> x + (snd y)) 0 results
The more general problem is that it would be really nice to have a way to print values of various types without writing the code yourself for each case. For that you can use something like deriving.

Use Union-Find to get the equivalence classes

I have a simple code of union-find as below:
let rec find p x =
if p.(x) = x
then x
else
let y = find p (p.(x)) in
p.(x) <- y;
y;;
let union x y p =
p.(find p y) <- p.(find p x);
p
Example:
let a = [|0;1;2;3;4|]
let print_array a =
Array.iter (fun i -> Printf.printf "%i" i; print_string " ") a
let print_union =
let a = union 0 1 a in
print_string "Result union (0, 1): ";
print_array a;
print_string "\n"
the result will be:
Result union (0, 1): 0 0 2 3 4
I am having a hard time to go further to get the disjoint-set.
For instance the example above I want to get: {0,1},{2},{3},{4}
Thank you for your help.
For obvious reasons, you can't print that result without going through the whole structure.
So, you want to collect inhabitants from all of your union-find:
let print_classes a =
(* Let's first create an array for storing the classes *)
let classes = Array.make (Array.length a) [] in
(* Let's now populate it!
I'm going backwards in the array to have nicer printing *)
for i = (Array.length classes) - 1 downto 0
do classes.(a.(i)) <- i :: (classes.(a.(i))) done;
(* And now the printing *)
Array.iter (function
| [] -> ()
| h::t -> Printf.printf "{%d%a}" h
(fun c -> List.iter (fun x -> Printf.fprintf c ",%i" x)) t
)
classes
I used Printf functions for the sake of brevity, you can find their doc here.
Note that this could probably be improved as it creates a potentially big array that may be "almost not" populated. depending on the frequency in which you'll use this function, you may want to store the equivalence class along with the class leader (I had to do that once, I used Set and Map from the stdlib).

Compose total and partial functions

I can't wrap my head around where should I put parenthesis to get it working:
let read_lines filename =
let channel = open_in filename in
Std.input_list channel;;
let print_lines filename =
List.map print_string ((^) "\n") (read_lines filename);;
^ This is the closes I've got so far. If my terminology is vague: ((^) "\n") is what I call partial function (well, because it doesn't handle all of its arguments). print_string I call total function because... well, it handles all of its arguments.
Obviously, what I would like to happen is that:
List.map applies first ((^) "\n") to the element of the list.
List.map applies print_string to the result of #1.
How? :)
Maybe you want something like that?
# let ($) f g = fun x -> f(g x);;
val ( $ ) : ('a -> 'b) -> ('c -> 'a) -> 'c -> 'b = <fun>
# let f = print_string $ (fun s -> s^"\n");;
val f : string -> unit = <fun>
# List.iter f ["a";"b";"c";"d"];;
a
b
c
d
- : unit = ()
# let g = string_of_int $ ((+)1) $ int_of_string;;
val g : string -> string = <fun>
# g "1";;
- : string = "2"
Your code didn't work because missing parenthesis:
List.map print_string ((^) "\n") xs
is parsed as
(List.map print_string ((^) "\n")) xs
when you expected
List.map (print_string ((^) "\n")) xs
A few things: List.map is probably not what you want, since it will produce a list (of unit values) rather than just iterating. ((^) "\n") is probably also not what you want, as it prepends a newline, the "\n" being the first argument. (This is not a section as in Haskell, but a straightforward partial application.)
Here's a reasonable solution that is close to what (I think) you want:
let print_lines filename =
List.iter (fun str -> print_string (str ^ "\n")) (read_lines filename)
But I would rather write
let print_lines filename =
List.iter (Printf.printf "%s\n") (read_lines filename)
Which is both clearer and more efficient.

Print a List in OCaml

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?
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.
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.
print_string (String.concat " " (List.map string_of_int list))
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.
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")];;
I would do this in the following way:
let a = [1;2;3;4;5];;
List.iter print_int a;;
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 ","
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]" print_l [1;2;3] ;;
[1;2;3]- : unit = ()
# printf "[%a]" print_l [];;
[]- : unit = ()
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