Ocaml read list from file - list

I need to take list of list of integers from file and use my func combine to it. See please on my code, where is my mistake?
# let f x l = List.filter ((<>) x) l
let rec comb = function
| [] -> []
| x::[] -> [[x]]
| l ->
List.fold_left (fun acc x -> acc # List.map (fun p -> x::p) ( comb ( f x l))) [ ] l ;;
let file = "example.dat"
let message = [[1;2];[3;4]]
let () =
let oc = open_out file in
fprintf oc "%s\n" message;
close_out oc;
let ic = open_in file in
try
let line = input_line ic in
print_endline line;
flush stdout;
close_in ic
with e ->
close_in_noerr ic;
raise e;;

Compilation fails here : fprintf oc "%s\n" message; because %s expects a string whereas message is of type int list list.
You have to iterate fprintf accross the list :
List.iter (fun l ->
List.iter (fun i -> fprintf oc "%d ") l) message;
The complete code :
let file = "example.dat"
let message = [[1;2];[3;4]]
let () =
let oc = open_out file in
List.iter (fun l -> List.iter (fun x -> fprintf oc "%d\n" x) l) message ;
close_out oc;
let ic = open_in file in
try
let line = input_line ic in
print_endline line;
flush stdout;
close_in ic
with e ->
close_in_noerr ic;
raise e;;

Related

OCaml Reading from file and perform some validation

can you help me out, i made this program to get an output from some .txt file like this :
john:3:uk
paul:18:us
#load "str.cma"
let f_test = "/home/test.txt" ;;
(*
Recursive Reading function
*)
let read_lines f_test : string list =
if Sys.file_exists (f_test) then
begin
let ic = open_in f_test in
try
let try_read () =
try Some (input_line ic) with End_of_file -> None in
let rec loop acc = match try_read () with
| Some s -> loop (s :: acc)
| None -> close_in_noerr ic; List.rev acc in
loop []
with e ->
close_in_noerr ic;
[]
end
else
[]
;;
(*Using Records*)
type user =
{
name : string;
age : int;
country : string;
};;
(*
Function to separated info in list
*)
let rec splitinfo ?(sep=":") l = match l with
| [] -> []
| x::xs -> (Str.split (Str.regexp ":") x)::splitinfo xs;;
(*
Function to get users position
*)
let get_user l:user =
let age = int_of_string (List.nth l 1) in
let user_name = List.nth l 0 in
{
name = user_name;
age = age ;
country = List.nth l 2;
};;
(*
Function to check some parameter is valid
*)
let par1 u: int =
if (u.age = 3) then
1
else
0;;
(*
Reporting function
*)
let report_statistics list_users =
let child = ref 0 in
let teenager = ref 0 in
let adult = ref 0 in print_string (" ----- -- Stats -- ----- \n" ) ;
List.iter (
fun user_l -> (
match user_l with
| [] -> print_string("> no user <\n")
| _ ->
let user = get_user user_l in
if (par1 user = 1) then (
print_string (" "^ user.name ^" --> Child \n" ) ;
child := !child + 1;
)
else
print_string (" "^ user.name ^" --> Other \n" );
)
) list_users;
print_string ("------- List ---- ");
print_newline();
print_string ("Child " );
print_int(!child);
print_newline();
print_string ("Teenager ") ;
print_int(!teenager);
print_newline();
print_string ("Adult ");
print_int(!adult);
print_newline();
;;
The program compile but doesn't output any result ...
What am i missing ?
I kept the function to check parameters simple so i can understand it better but can't figure it out why it isn't outputing any result
Can you help me out here ?
Thanks in advance :)
The code as given defines some functions such as read_lines and report_statistics. But there are no calls to these functions.
If there is no other OCaml source involved, this is probably your problem. You need to call the functions.
It is fairly customary to have a "main" function that does the work of an OCaml program, and then (this is key) you have to actually call the main function:
let main () =
(* Call the functions that do the work of the program *)
let () = main ()
I have many times forgotten this last line and then nothing happens when I run the program.

Ocaml won't let me name my List

the code :
open Hashtbl;;
type 'a option = None | Some of 'a;;
let ht = create 0;;
let rec charCount fd =
let x =
try Some (input_char fd)
with End_of_file -> None
in
match x with
| Some c ->
let v =
try find ht c
with Not_found -> 0
in
replace ht c (v+1);
charCount fd
| None -> ();;
let loadHisto fn =
let fd = open_in fn in
charCount fd;;
let rec printList l = match l with
| [] -> print_newline ()
| h::t -> print_char h; print_string " "; printList t;;
let hashtbl_keys h = Hashtbl.fold (fun key _ l -> key :: l) h [];;
let compare_function a b = compare (find ht b) (find ht a);;
let akeys = List.sort compare_function (hashtbl_keys ht);;
printList (List.sort compare_function (hashtbl_keys ht));;
printList akeys;;
and the result :
ocaml histo.ml
e t s u a i n p j (*here is the first printList*)
(*and here should be the second one, but there is only a blank*)
Here is the problem :
I sorted a list, and tried to display it's content but as you can see, it doesn't seem like I can give a name to my resulting List
Edit :
I don't think it's a buffer problem because even if I only print akeys, there is nothing
Edit : I added the code asked for below
And ht is a hashtbl, and it contains what it should contain (I checked this)

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

How to convert such a lisp function to ocaml?

The function "good-red" used to calculate the 18 highest frequency numbers from a file ssqHitNum.txt.
(defun good-red ()
(let ((tab (make-hash-table)) (res '()) (nums) (sort-res))
(dotimes (i 33) (setf (gethash (+ i 1) tab) 0))
(with-open-file (stream "ssqHitNum.txt")
(loop :for line = (read-line stream nil)
:until (null line)
:do
(setq nums (butlast (str2lst (subseq line 6))))
(dolist (n nums) (incf (gethash n tab)))
))
(maphash #'(lambda (k v) (push (cons k v) res)) tab)
(setq sort-res (sort res #'> :key #'cdr))
;(print sort-res)
(subseq (mapcar #'car sort-res) 0 18)))
$head ssqHitNum.txt
10000 7 12 18 19 22 28 4
10000 16 17 23 26 31 32 11
10000 3 4 18 22 24 29 11
10000 4 9 10 18 29 32 8
10000 5 7 10 14 17 25 11
The number is between 1 and 33. Whether or not i use a hashtab and scan the file line by line as the Common Lisp code does in ocaml ? Or there is more elegant way using ocaml ?
Any suggestion is appreciated !
FWIW, in F# 3.0 you can just write it like this:
System.IO.File.ReadLines #"ssqHitNum.txt"
|> Seq.collect (fun s -> s.Split ' ' |> Seq.skip 1)
|> Seq.countBy id
|> Seq.sortBy (fun (_, p) -> -p)
|> Seq.take 18
In OCaml, I'd start by writing these useful library functions from scratch:
let readAllLines file =
let lines = ref [] in
let input = open_in file in
begin
try
while true do
lines := input_line input :: !lines
done
with
| End_of_file ->
close_in input
end;
List.rev !lines
let collect f xs =
List.concat (List.map f xs)
let countBy f xs =
let counts = Hashtbl.create 100 in
let find key = try Hashtbl.find counts (f key) with Not_found -> 0 in
let add key = Hashtbl.replace counts (f key) (1 + find key) in
List.iter add xs;
Hashtbl.fold (fun k n kns -> (k, n)::kns) table []
let sortBy f xs =
List.sort (fun x y -> compare (f x) (f y)) xs
let rec truncate n xs =
match n, xs with
| 0, _ | _, [] -> []
| n, x::xs -> x::truncate (n-1) xs
let rec skip n xs =
match n, xs with
| 0, xs -> xs
| n, [] -> []
| n, _::xs -> skip (n-1) xs
let (|>) x f = f x
let id x = x
and then write it the same way:
readAllLines "ssqHitNum.txt"
|> collect (fun s -> split ' ' s |> skip 1)
|> countBy id
|> sortBy (fun (_, p) -> -p)
|> truncate 18
The F# is still better because the lines are read on-demand whereas my OCaml reads everything into memory up-front.
From a similarly high-level point of view, using Batteries:
open Batteries_uni
let freq file best_n =
let table = Hashtbl.create 100 in
let freq_num num =
Hashtbl.replace table num (1 + Hashtbl.find_default table num 0) in
let freq_line line =
let nums = List.tl (String.nsplit line " ") in
List.iter freq_num nums in
Enum.iter freq_line (File.lines_of file);
let cmp (_,freq1) (_,freq2) = (* decreasing *) compare freq2 freq1 in
Hashtbl.enum table |> List.of_enum
|> List.sort ~cmp
|> List.take best_n
To test, from the toplevel:
#use "topfind";;
#require "batteries";;
#use "/tmp/test.ml";;
test "/tmp/test.txt" 18;;
As asked by z_axis, here is another solution using only the base library distributed with the OCaml compiler. It is a bit more verbose due to the absence of some convenience functions.
let freq file best_n =
let table = Hashtbl.create 100 in
let freq_num num =
Hashtbl.replace table num
(1 + try Hashtbl.find table num with Not_found -> 0) in
begin
let input = open_in file in
try while true do
let line = input_line input in
let nums = List.tl (Str.split (Str.regexp " +") line) in
List.iter freq_num nums
done with End_of_file -> close_in input
end;
let sorted =
let cmp (_,freq1) (_,freq2) = (* decreasing *) compare freq2 freq1 in
List.sort cmp (Hashtbl.fold (fun k x li -> (k,x)::li) table []) in
(* take not tail-rec, not a problem for small n such as n=18 *)
let rec take n = function
| li when n = 0 -> []
| [] -> []
| hd::tl -> hd :: take (n - 1) tl in
take best_n sorted
The regexp module Str is not linked by default, even if it is in the default search path, so you must explicitly compile the program with str.cma (for ocamlc) or str.cmxa (for ocamlopt). In the toplevel, #use "topfind";; then #require "str";; will do.
With a fixed set of small integers it may be simpler to use an array:
let good_red () =
let a = Array.make 33 0 in
let bump i = a.(i-1) <- a.(i-1) + 1 in
let rec iter_lines fh =
try
let words = Str.split (Str.regexp " +") (input_line fh) in
List.iter bump (List.map int_of_string (List.tl words));
iter_lines fh
with End_of_file -> () in
let fh = open_in "ssqHitNum.txt" in
iter_lines fh;
close_in fh;
let b = Array.mapi (fun i freq -> (i+1,freq)) a in
Array.sort (fun (i1,f1) (i2,f2) -> compare f2 f1) b;
Array.sub b 0 18;;
try
Array.iter (fun (i,freq) -> Printf.printf "%2d %2d\n" freq i) (good_red ())
with Invalid_argument _ -> print_endline "bad input"
As gasche mentions you need to compile with str.cma or str.cmxa.
I'm not sure to understand the problem you want to solve. (Why all your input lines start with 10000?)
If you just want to find the 18-th highest frequency numbers, you don't need to read line by line (and this is true in Lisp, in C, in Ocaml, ...), and Ocaml's Scanf.scanf "%d" (fun x -> ...) could do the input.
And using an Hashtbl.t is sensible in Ocaml.