let string s = "";;
let string s =
for i = 0 to 5 do
Printf.sprintf "%s" s
done;;
I want to printf with string type in loop (ex-string "hi" -> "hihihihihi")
When I use for, It makes string to unit and It doesnt' work.
How to loop print with string type?
There are few ways to do it with a buffer or format, with the right complexity.
First, the more imperative version is probably with a buffer
let string_repeat_n_time s n =
let b = Buffer.create (String.length s * n) in
for i = 1 to n do
Buffer.add_string b s
done;
Buffer.contents b
Buffer are made to handle efficiently repeated addition, so they are the right data structure.
A more functional version would be to use recursion with Format.fprintf (Format is essentially an improved version of Printf)
let string_n_times s n =
let rec repeat ppf n =
if n = 0 then Format.fprintf ppf "%!"
else
Format.fprintf ppf "%s%a" s repeat (n-1) in
Format.asprintf "%a" repeat n ;;
This code is using a Buffer under the hood thus the complexity is the same as before. If we make the buffer explicit, we can have an imperative code that is using the format printer
let string_n_times s n =
let b = Buffer.create (String.length s * n) in
let ppf = Format.formatter_of_buffer b in
for i = 1 to n do
Format.fprintf ppf "%s" s
done;
Format.fprintf ppf "%!" (* flush *);
Buffer.contents b
which can be useful if we are adding something more complex than a string to the buffer.
Something like this:
let string_n_times s n =
let str = ref "" in
for i = 1 to n do
str := !str ^ s
done; !str
let () = print_endline (string_n_times "hi" 5)
Is this what you are trying to accomplish?
let string_n_times s n =
for i = 0 to n do
Printf.printf "%s" s
done
let () = string_n_times "Hi" 5
Related
I defined a custom pretty-printer that takes a message, customise it and prints it:
let mypp ppf msg =
Format.fprintf ppf "Hello";
Format.fprintf ppf msg
Now, I wanted to use it to print to a string but since I want to use it multiple times I wanted to put it in a function:
let myspp msg =
let _ = mypp Format.str_formatter msg in
Format.flush_str_formatter ()
But I can't write what I want:
12 | let s = myspp "Bleh %s" "world" in
^^^^^
Error: This function has type ('a, Format.formatter, unit) format -> string
It is applied to too many arguments; maybe you forgot a `;'.
Even worse, if I delete the argument:
let () =
let s = myspp "Bleh %s" in
Format.eprintf "---%s---#." s
Results in:
---Hello: ---
The formatting string disappeared.
I know I'm missing something but can't find it. I tried using kfprintf but didn't have good results. Maybe I need to change my original function?
It should be noted that if I don't use it in a function it works as wanted:
let () =
mypp Format.str_formatter "Blah %s" "blih";
Format.eprintf "---%s---#." (Format.flush_str_formatter ())
Results in:
---Hello: Blah blih---
Since you want to run some function after that all format arguments have been provided, the only option is to use kfprintf:
let to_string msg =
let b = Buffer.create 17 in
let ppf = Format.formatter_of_buffer b in
Format.fprintf ppf "Hello: ";
Format.kfprintf (fun ppf ->
Format.pp_print_flush ppf ();
Buffer.contents b
) ppf msg
let s = to_string "%d + %d = %d" 1 2 3
It is also better to avoid Format.str_formatter since this avoid introducing a global mutable state in your program.
EDIT:
If the important point is to reuse the mypp function, the simplest fix is to add a continuation argument to mypp:
let kmypp k ppf msg =
Format.fprintf ppf "Hello";
Format.kfprintf k ppf msg
let to_string msg =
let b = Buffer.create 17 in
let ppf = Format.formatter_of_buffer b in
kmypp (fun ppf ->
Format.pp_print_flush ppf ();
Buffer.contents b
) ppf msg
I am newbie to SML, trying to write recursive program to delete chars from a string:
remCharR: char * string -> string
So far wrote this non-recursive prog. Need help to write recursive one.
- fun stripchars(string,chars) = let
= fun aux c =
= if String.isSubstring(str c) chars then
= ""
= else
= str c
= in
= String.translate aux string
= end
= ;
You have already found a very idiomatic way to do this. Explicit recursion is not a goal in itself, except perhaps in a learning environment. That is, explicit recursion is, compared to your current solution, encumbered with a description of the mechanics of how you achieve the result, but not what the result is.
Here is one way you can use explicit recursion by converting to a list:
fun remCharR (c, s) =
let fun rem [] = []
| rem (c'::cs) =
if c = c'
then rem cs
else c'::rem cs
in implode (rem (explode s)) end
The conversion to list (using explode) is inefficient, since you can iterate the elements of a string without creating a list of the same elements. Generating a list of non-removed chars is not necessarily a bad choice, though, since with immutable strings, you don't know exactly how long your end-result is going to be without first having traversed the string. The String.translate function produces a list of strings which it then concatenates. You could do something similar.
So if you replace the initial conversion to list with a string traversal (fold),
fun fold_string f e0 s =
let val max = String.size s
fun aux i e =
if i < max
then let val c = String.sub (s, i)
in aux (i+1) (f (c, e))
end
else e
in aux 0 e0 end
you could then create a string-based filter function (much alike the String.translate function you already found, but less general):
fun string_filter p s =
implode (fold_string (fn (c, res) => if p c then c::res else res) [] s)
fun remCharR (c, s) =
string_filter (fn c' => c <> c') s
Except, you'll notice, it accidentally reverses the string because it folds from the left; you can fold from the right (efficient, but different semantics) or reverse the list (inefficient). I'll leave that as an exercise for you to choose between and improve.
As you can see, in avoiding String.translate I've built other generic helper functions so that the remCharR function does not contain explicit recursion, but rather depends on more readable high-level functions.
Update: String.translate actually does some pretty smart things wrt. memory use.
Here is Moscow ML's version of String.translate:
fun translate f s =
Strbase.translate f (s, 0, size s);
with Strbase.translate looking like:
fun translate f (s,i,n) =
let val stop = i+n
fun h j res = if j>=stop then res
else h (j+1) (f(sub_ s j) :: res)
in revconcat(h i []) end;
and with the helper function revconcat:
fun revconcat strs =
let fun acc [] len = len
| acc (v1::vr) len = acc vr (size v1 + len)
val len = acc strs 0
val newstr = if len > maxlen then raise Size else mkstring_ len
fun copyall to [] = () (* Now: to = 0. *)
| copyall to (v1::vr) =
let val len1 = size v1
val to = to - len1
in blit_ v1 0 newstr to len1; copyall to vr end
in copyall len strs; newstr end;
So it first calculates the total length of the final string by summing the length of each sub-string generated by String.translate, and then it uses compiler-internal, mutable functions (mkstring_, blit_) to copy the translated strings into the final result string.
You can achieve a similar optimization when you know that each character in the input string will result in 0 or 1 characters in the output string. The String.translate function can't, since the result of a translate can be multiple characters. So an alternative implementation uses CharArray. For example:
Find the number of elements in the new string,
fun countP p s =
fold_string (fn (c, total) => if p c
then total + 1
else total) 0 s
Construct a temporary, mutable CharArray, update it and convert it to string:
fun string_filter p s =
let val newSize = countP p s
val charArr = CharArray.array (newSize, #"x")
fun update (c, (newPos, oldPos)) =
if p c
then ( CharArray.update (charArr, newPos, c) ; (newPos+1, oldPos+1) )
else (newPos, oldPos+1)
in fold_string update (0,0) s
; CharArray.vector charArr
end
fun remCharR (c, s) =
string_filter (fn c' => c <> c') s
You'll notice that remCharR is the same, only the implementation of string_filter varied, thanks to some degree of abstraction. This implementation uses recursion via fold_string, but is otherwise comparable to a for loop that updates the index of an array. So while it is recursive, it's also not very abstract.
Considering that you get optimizations comparable to these using String.translate without the low-level complexity of mutable arrays, I don't think this is worthwhile unless you start to experience performance problems.
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).
I'm trying to get a pretty print function to print the query result of my database in OCaml. I've been following this approach http://mancoosi.org/~abate/ocaml-format-module
I have this code so far:
let pp_cell fmt cell = Format.fprintf fmt "%s" cell;;
let pp_header widths fmt header =
let first_row = Array.map (fun x -> String.make (x + 1) ' ') widths in
Array.iteri (fun j cell ->
Format.pp_set_tab fmt ();
for z=0 to (String.length header.(j)) - 1 do cell.[z] <- header.(j).[z] done;
Format.fprintf fmt "%s" cell
) first_row
let pp_row pp_cell fmt row =
Array.iteri (fun j cell ->
Format.pp_print_tab fmt ();
Format.fprintf fmt "%a" pp_cell cell
) row
let pp_tables pp_row fmt (header,table) =
(* we build with the largest length of each column of the
* table and header *)
let widths = Array.create (Array.length table.(0)) 0 in
Array.iter (fun row ->
Array.iteri (fun j cell ->
widths.(j) <- max (String.length cell) widths.(j)
) row
) table;
Array.iteri (fun j cell ->
widths.(j) <- max (String.length cell) widths.(j)
) header;
(* open the table box *)
Format.pp_open_tbox fmt ();
(* print the header *)
Format.fprintf fmt "%a#\n" (pp_header widths) header;
(* print the table *)
Array.iter (pp_row fmt) table;
(* close the box *)
Format.pp_close_tbox fmt ();
;;
(** Pretty print answer set of a query in format of
* col_name 1 | col_name 2 | col_name 3 |
* result1.1 | result2.1 | result3.1 |
* result1.2 | result2.2 | result3.2 |
* #param col_names provides the names of columns in result outp ut *)
let pretty_print fmt pp_cell (col_names, tuples) =
match col_names with
| [] -> printf "Empty query\n"
| _ ->
printf "Tuples ok\n";
printf "%i tuples with %i fields\n" (List.length tuples) (List.length col_names);
print_endline(String.concat "\t|" col_names);
for i = 1 to List.length col_names do printf "--------" done; print_newline() ;
let print_row = List.iter (printf "%s\t|") in
List.iter (fun r -> print_row r ; print_newline ()) tuples;
for i = 1 to List.length col_names do printf "--------" done; print_newline() ;
let fmt = Format.std_formatter in
Format.fprintf fmt "%a" (pp_tables (pp_row pp_cell)) (Array.of_list col_names,tuples);
flush stdout
;;
let print_res (col_names, tuples) =
let fmt = Format.std_formatter in
pretty_print fmt pp_cell (col_names, tuples)
;;
The problem is in the line
Format.fprintf fmt "%a" (pp_tables (pp_row pp_cell)) (Array.of_list col_names,tuples);
basically because I need tuples to be and string array array (a matrix) while its type is string list list. So I tried to solve it by converting the list list into a matrix following this approach http://www.siteduzero.com/forum-83-589601-p1-ocaml-convertir-un-list-list-en-array-array.html with this code:
let listToMatrix lli =
let result = Array.init 6 (fun _ -> Array.create 7 2)
let rec outer = function
| h :: tl, col ->
let rec inner = function
| h :: tl, row ->
result.[row].[col] <- h
inner (tl, row + 1)
| _ -> ()
inner (h, 6 - List.length h)
outer (tl, col + 1)
| _ -> ()
outer (lli, 0)
result
;;
But I just a syntax error while compiling:
File "src/conn_ops.ml", line 137, characters 2-5:
Error: Syntax error
make: *** [bin/conn_ops.cmo] Error 2
I don't really know what to do, or how I can accomplish the conversation of the list list into the matrix. My approach is the correct? This has been the first time I've worked with OCaml and it's been quite a pain in the *, so please, try to be kind with me :D
This is a lot of code to read in detail, but it looks like you're missing a semicolon after result.[row].[col] <- h. However, this code looks suspicious to me. The notation .[xxx] is for accessing individual characters of a string. You want to use array index notation .(xxx), seems to me.
Here is a function that changes a string list list to a string array array. Maybe it will be useful:
let sll_to_saa sll = Array.of_list (List.map Array.of_list sll)
Actually, this function changes any list of lists to an array of arrays; it doesn't have to be strings.
I'm not sure I understood your entire post, but if you want to convert
a string list list into a string array array, you can do this
quite easily with the Array.of_list function:
# let strings = [["hello"; "world"]; ["foo"; "bar"]];;
val strings : string list list = [["hello"; "world"]; ["foo"; "bar"]]
# Array.of_list (List.map Array.of_list strings);;
- : string array array = [|[|"hello"; "world"|]; [|"foo"; "bar"|]|]
I hope this helped.
Your function is not syntacticly correct. Below is a fixed version:
let listToMatrix lli =
let result = Array.init 6 (fun _ -> Array.create 7 2) in
let rec outer = function
| h :: tl, col ->
let rec inner = function
| h :: tl, row ->
result.(row).(col) <- h;
inner (tl, row + 1)
| _ -> ()
in
inner (h, 6 - List.length h);
outer (tl, col + 1)
| _ -> ()
in
outer (lli, 0);
result
;;
As noted in other answers:
the subscript operators for arrays are parentheses,
some semi-colons are missing,
sometimes you forget to use the keyword in to mark the expression where your definition will be used.
Please note that I didn't check if the function does what it is supposed to do.
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
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
Try this:
let explode s = List.init (String.length s) (String.get s)
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));;
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;;
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
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;;
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;;