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
Related
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;;
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.
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
I have a program where if I type "tac Text.txt" (or any file path in quotations, but this is the test text file I made/used), it will print what is in the txt file, but in reverse. But it doesn't work properly. Where it should appear as
No it is not.
Yes-it is.
No it is not.
Hello my name is Jim.
it appears as
["No it is not."; ""; ""; "Yes-it is."; "No it is not."; "Hello my
name is Jim."].
My code currently is
open System
open System.IO
let countLines path =
File.ReadAllLines(path) |> Seq.toList|> List.rev
// File.ReadAllLines reads the file, turns it into a list then reverses the list.
let printFunction lines =
printfn "%A" lines
// This, when called, will print the file in reverse.
let tac path =
if File.Exists(path) then
let lines = countLines path
printFunction lines
else
printfn "File not found."
[<EntryPoint>]
let main argv =
if argv.Length > 0 then
tac argv.[0]
else
printfn "Error - Please enter file path."
0
I'm assuming it's due to converting to a list, is there a way I can print it normally? I'm hoping it's just a small rookie mistake I've made.
UPDATE: I just changed
let countLines path =
File.ReadAllLines(path) |> Seq.toList|> List.rev
to
let countLines path =
File.ReadAllLines(path) |> Array.rev
Same thing happens, but I'm hoping it leads me closer to the result I want.
It's writing out your entire data type, which is a string list.
You need to iterate through the list:
let printFunction lines =
for line in lines do printfn "%s" line
Print an array, list or seq of lines individually:
let printFunction = Seq.iter (printfn "%s")
I am new to OCaml, and now I am trying to make a simple REPL.
let rec repl () =
print_prompt () ;
let input = Scanf.scanf "%s" (fun x -> x) in
if input = "" then repl ()
else print_endline input
let print_prompt () = print_string "> "
The problem now i am having is: when program starts, it does not display prompt immediately. It waits for my input and prints prompt along with my input.
What I want is:
> "user_input"
"user_input"
But i am getting :
"user_input"
> "user_input"
How can I fix this?
Using readline instead of Scanf :
val read_line : unit -> string
Flush standard output, then read characters from standard input until a newline character is encountered. Return the string of all characters read, without the newline character at the end.
Well, you didn't show the print_promt implementation, but I can guess, that it uses some buffered io function like print_string or printf. They print into an intermediate buffer and data will not be displayed unless flush is called. You can use flush or flush_all functions to do this manually. Also you can use a special specificator %! in printf formats string:
open Printf
let print_prompt () = printf "> %!"
This is almost certainly a buffering problem. In your print_prompt function, flush the standard output:
flush stdout