Why can I not print this input a second time in OCaml? - ocaml

I am very new to OCaml and am attempting to learn and write a program at the same time. I am writing a palindrome program. I am attempting to get a string from the user such as d e v e d or Hello World! or loud all of the preceding are valid user input. I need to read these strings and display them then reverse them and check if it is a palindrome or not. I did the following code...
print_string "Enter a string: ";
let str = read_line () in
Printf.printf "%s\n" str;;
Printf.printf "%s\n" str;;
this works fine and will give the print, Enter a string: d e v e d or Enter a string: Hello World! The issue comes when I try to add another Printf.printf "%s\n" str;; into the code. it gives me an error of File "main.ml", line 5, characters 21-24:
Error: Unbound value str with line 5 being the line of the 2nd Printf.printf statement. I have tried this with no ; for both of the print statements, with 1 or with 2 and I get the same error each time. Does anyone with more OCaml knowledge know why I get this error.

Because of your use of in your code parses as:
(let str = read_line () in Printf.printf "%s\n" str);;
and then a completely separate:
Printf.printf "%s\n" str;;
So str is local to the first printf.
You want:
let str = read_line ();;
Printf.printf "%s\n" str;;
Printf.printf "%s\n" str;;
which is three separate definitions. The first defines a global variable str.

Related

Prompt for string and read and then display in OCaml

I've spent a few days playing around with OCaml
let prompt_user() = print_string "Enter a string\n";;
let read_user_input2() =
prompt_user();
input_line stdin;;
When run, nothing happens, but I can start entering information. Only after entering the string does the actual prompt appear:
# read_user_input();;
hello
Enter a string
You entered hello
- : string = "hello"
#
Can someone tell me how I should be reordering my program so that the prompt appears before the input stage?
Many TIA
The standard output channel is buffered, but print_string does not flush the buffer. print_endline and print_newline does, however, as does flush of course, so either of these should work:
let prompt_user () = print_endline "Enter a string"
let prompt_user () =
print_string "Enter a string";
print_newline ()
let prompt_user () =
print_string "Enter a string\n";
flush stdout

Ocaml syntax quite weird

I have this program in Ocaml that reads a line from keyboard and returns an int :
let get_int () =
print_string "Insert a number\n" ;
let input = read_line() in
let return__ = int_of_string( input )
;;
print_string "I'll print what you write : ";
print_int ( get_int() );
print_string "\n"
The problem is a syntax error on line 5, ";;" said the compiler.
I know that already exist functions that do this but I'm doing this to learn.
I read the official Ocaml documentation but I still don't get the syntax.
Someone that could explain me something about it?
Your get_int-binding has to end in an expression. You can get rid of the last let-binding there and return the int directly:
let get_int () =
print_string "Insert a number\n";
let input = read_line () in
int_of_string input;;

OCAML Taking multiple arguments from stdin and operating on them one by one

I have written an interpreter using ocamllex and ocamlyacc, the lexer and the parser work correctly but currently they only parse the last .txt argument it receives as oppose to all of them in turn. For example, ./interpret one.txt two.txt three.txt only parses three.txt as oppose to parsing one.txt and then two.txt and then three.txt which is what I want. So for example the parse results are as follows:
one.txt -> "1"
two.txt -> "2"
three.txt -> "3"
On calling ./interpret one.txt two.txt three.txt the current output is: 3 but I want it to be 123
Here is my main class which deals with the stdin and stdout
open Lexer
open Parser
open Arg
open Printf
let toParse c =
try let lexbuf = Lexing.from_channel c in
parser_main lexer_main lexbuf
with Parsing.Parse_error -> failwith "Parse failure!" ;;
let argument = ref stdin in
let prog p = argument := open_in p in
let usage = "./interpreter FILE" in
parse [] prog usage ;
let parsed = toParse !argument in
let result = eval parsed in
let _ = parsed in
flush stdout;
Thanks for your time
There's not really enough code here to be able to help.
If I assume that the output is written by eval, then I see only one call to eval. But there's nothing here that deals with filenames from the command line, so it's hard to say more.
If you are planning to read input from files, then there's no reason to be using stdin for anything as far as I can tell.
(I know this is a very minor point, but this code doesn't constitute a class. Other languages use classes for everything, but this is a module.)
Update
Here's a module that works something like the Unix cat command; it writes out the contents of all the files from the command line one after the next.
let cat () =
for i = 1 to Array.length Sys.argv - 1 do
let ic = open_in Sys.argv.(i) in
let rec loop () =
match input_line ic with
| line -> output_string stdout (line ^ "\n"); loop ()
| exception End_of_file -> ()
in
loop ();
close_in ic
done
let () = cat ()
Here's how it looks when you compile and run it.
$ ocamlc -o mycat mycat.ml
$ echo test line 1 > file1
$ echo test line 2 > file2
$ ./mycat file1 file2
test line 1
test line 2

How to get a formatted string in OCaml?

In OCaml, I can use Printf.printf to output formatted string, like
Printf.printf "Hello %s %d\n" world 123
However, printf is a kind of output.
What I wish for is not for output, but for a string. For example, I want
let s = something "Hello %s %d\n" "world" 123
then I can get s = "Hello World 123"
How can I do that?
You can use Printf.sprintf:
# Printf.sprintf "Hello %s %d\n" "world" 123;;
- : string = "Hello world 123\n"
You can do this:
$ ocaml
OCaml version 4.00.1
# let fmt = format_of_string "Hello %s %d";;
val fmt : (string -> int -> '_a, '_b, '_c, '_d, '_d, '_a) format6 = <abstr>
# Printf.sprintf fmt "world" 123;;
- : string = "Hello world 123"
The format_of_string function (as the name implies) transforms a string literal into a format. Note that formats must ultimately be built from string literals, because there is compiler magic involved. You can't read in a string and use it as a format, for example. (It wouldn't be typesafe.)

What is the difference between these three fscanf calls in OCaml?

I wrote a short bit of code to simply skip num_lines lines in an input file (printing the lines out for debugging purposes. Here's two things I tried that didn't work:
for i = 0 to num_lines do
print_endline (fscanf infile "%s" (fun p -> p));
done;;
for i = 0 to num_lines do
print_endline (fscanf infile "%S\n" (fun p -> p));
done;;
But this one did work:
for i = 0 to num_lines do
print_endline (fscanf infile "%s\n" (fun p -> p));
done;;
I've been trying to comprehend the documentation on fscanf, but it doesn't seem to be sinking in. Could someone explain to me exactly why the last snippet worked, but the first two didn't?
"%s" -- Matches everything to next white-space ("\n" here) but never matches "\n"
"%S\n" -- Matches thing that looks like Ocaml strings, then a "\n"
"%s\n" -- Matches everything to next white-space ("\n" here) then "\n". This will act different if there is no trailing "\n" in file or if there is a space before the "\n", etc.
"%s " -- Matches anything up to white-space, and then all trailing white-space including "\n" (or possibly even no white-space). This works because " " means "any white space, possible none", in the format string.