How to convert strings to Num.num in OCaml? - ocaml

I'm looking for a function that converts a string representation of a decimal number into a Num.num. There is a Num.num_of_string function but, sadly, it only works for valid integers.
I'm asking before reimplementing one such function.

You'll have to do it yourself, I think. I did it once, here's what I did :
let num_of_string =
let open Num in
let code_0 = Char.code '0' in
let num10 = Int 10 in
fun s ->
try num_of_string s
with Failure _ ->
let r = ref (Int 0) in
let pos_dot = ref (-1) in
String.iteri (fun i c ->
if c = '.' then pos_dot := String.length s - i
else
r := add_num (mult_num num10 !r) (num_of_int (Char.code c - code_0))
) s;
assert (!pos_dot <> -1);
div_num !r (power_num num10 (num_of_int !pos_dot))

Related

Ocaml loop for string printf

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

How to properly use whileloop to return afterwhileloop value

The goal is to write a parse tree generator that takes as input an arithmetic expression of type string and output a parse tree. In the provided codes below, we can see three mutually recursive methods expr(), term(), primary(). expr() has to return a parse tree by going through the input arithmetic expression string. The parse rules are defined by Exp -> Term|{+Term}, Term -> Primary*Primary, Primary -> a|b|c...|z|(Exp). The codes can generate the correct parse tree if there is only one + used. For example, with an input string like "a+b", the codes produce Exp( '+', Var a, Var b ). The code fails in expression with more than one +. For example, a+b+c gives Exp('+', Var a, Var b) but it should really be Exp('+', Var a, Exp('+', Var b ,Var c).
exception NotImplemented
type exptree = Var of char | Expr of char * exptree * exptree
let charSet =['a'; 'b'; 'c'; 'd'; 'e'; 'f'; 'g'; 'h'; 'i'; 'j'; 'k'; 'l'; 'm'; 'n'; 'o';
'p'; 'q'; 'r'; 's'; 't'; 'u'; 'v'; 'w'; 'x'; 'y'; 'z']
let rec isin charr charlist =
match charlist with
| []-> false
|q::w -> if q=charr then true else isin charr w
let parse (inputexp: string): exptree =
let sym = ref inputexp.[0] in
let cursor = ref 0 in
let getsym () =
cursor := !cursor + 1;
sym := inputexp.[!cursor]
in
let rec expr (): exptree =
let p = term() in
match !sym with
| '+' -> (getsym(); Expr ('+',p,term()))
| _ -> p
and term (): exptree =
let p = primary() in
match !sym with
| '*' -> getsym() ;Expr ('*',p,primary())
| _ -> p
and primary (): exptree =
if !sym = '('
then begin
getsym ();
let result = expr () in
if !sym <> ')' then
failwith "Mismatched parens"
else if !cursor = (String.length inputexp) - 1 then
result
else begin
getsym ();
result
end
end
else
if isin !sym charSet then
if !cursor = (String.length inputexp) - 1 then
Var !sym
else
let result = Var !sym in
begin
getsym ();
result
end
else
failwith "In primary"
in
expr ()
So this shows that we have a problem that expr does not go beyond the first + in the input string. While using a while loop seem promising. However, the recursive call returns a parse tree after it sees the first + rather than looking for the next one. Hence please help this one solve this problem.
If you want to return a value from the while loop you can use an exception. Here is the example, which uses a while true loop and escapes from it using an exception that uses the return as a payload
exception Finished of int
let compute m =
let n = ref 0 in
let r = ref 1 in
try
while true do
if !n < m
then begin
r := !r + !r;
incr n;
end
else
raise_notrace (Finished !r)
done;
assert false
with Finished x -> x;;
Note, that we have to add the assert false statement to tell the compiler that this line of code is unreachable. If your loop is not a while true loop and can terminate either normally or exceptionally, then it will loop like this:
let compute m =
let n = ref 0 in
let r = ref 1 in
try
while !n < m do
incr n;
r := !r + !r;
if !r > 4096 then raise_notrace (Finished !r)
done;
!r
with Finished x -> x;;
Note, this is, of course, a non-idiomatic code for OCaml, we prefer to use recursion to implement recursive algorithms. Also, unlike other languages, OCaml provides very cheap exceptions, so calling an exception is as cheap as using goto in C. We used the raise_notrace operator to raise an exception without recording the backtrace, to ensure this.

Trying to get first word from character list

I have a character list [#"h", #"i", #" ", #"h", #"i"] which I want to get the first word from this (the first character sequence before each space).
I've written a function which gives me this warning:
stdIn:13.1-13.42 Warning: type vars not generalized because of value
restriction are instantiated to dummy types (X1,X2,...)
Here is my code:
fun next [] = ([], [])
| next (hd::tl) = if(not(ord(hd) >= 97 andalso ord(hd) <= 122)) then ([], (hd::tl))
else
let
fun getword [] = [] | getword (hd::tl) = if(ord(hd) >= 97 andalso ord(hd) <= 122) then [hd]#getword tl else [];
in
next (getword (hd::tl))
end;
EDIT:
Expected input and output
next [#"h", #"i", #" ", #"h", #"i"] => ([#"h", #"i"], [#" ", #"h", #"i"])
Can anybody help me with this solution? Thanks!
This functionality already exists within the standard library:
val nexts = String.tokens Char.isSpace
val nexts_test = nexts "hi hi hi" = ["hi", "hi", "hi"]
But if you were to build such a function anyway, it seems that you return ([], []) sometimes and a single list at other times. Normally in a recursive function, you can build the result by doing e.g. c :: recursive_f cs, but this is assuming your function returns a single list. If, instead, it returns a tuple, you suddenly have to unpack this tuple using e.g. pattern matching in a let-expression:
let val (x, y) = recursive_f cs
in (c :: x, y + ...) end
Or you could use an extra argument inside a helper function (since the extra argument would change the type of the function) to store the word you're extracting, instead. A consequence of doing that is that you end up with the word in reverse and have to reverse it back when you're done recursing.
fun isLegal c = ord c >= 97 andalso ord c <= 122 (* Only lowercase ASCII letters *)
(* But why not use one of the following:
fun isLegal c = Char.isAlpha c
fun isLegal c = not (Char.isSpace c) *)
fun next input =
let fun extract (c::cs) word =
if isLegal c
then extract cs (c::word)
else (rev word, c::cs)
| extract [] word = (rev word, [])
in extract input [] end
val next_test_1 =
let val (w, r) = next (explode "hello world")
in (implode w, implode r) = ("hello", " world")
end
val next_test_2 = next [] = ([], [])

Simplify function returning module

This function should be able to simplify, removing the unnecessary let module T = .... But how?! I keep getting syntax errors. Tips?
let make_module dice_results : (module Tellstory.T) =
let dice_calls = ref 0 in (* nr of times dice has been called *)
let module T = Tellstory.Make(struct
let dice n =
let result = List.nth dice_results (!dice_calls) in
dice_calls := !dice_calls + 1;
result
end) in
(module T)
I can't check your module, but this is an example for inspiration:
let make_module () : (module Unit) =
(module Comparable.Make (struct type t = int with compare, sexp end))
Looks like that the following, should work:
let make_module dice_results : (module Tellstory.T) =
let dice_calls = ref 0 in (* nr of times dice has been called *)
(module Tellstory.Make(struct
let dice n =
let result = List.nth dice_results (!dice_calls) in
dice_calls := !dice_calls + 1;
result
end))

string to list of char

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;;