Unusual order-of-execution problem with OCaml - ocaml

I'm new to OCaml. I've written this very trivial program:
open Stdio
let getline =
match In_channel.input_line In_channel.stdin with
| Some x -> x
| None -> "No input"
;;
let () =
printf "What's your name? ";
printf "Hi, %s!" getline;;
and several variations thereof.
You get the idea. I ask for the user's name and print "Hi, [name]!".
It works but the output is in the wrong order. I build the project with dune, run the executable, don't get any prompt for the name, I type it in and then I get all at once "What's your name? Hi, [name]!".
Now, I know the basics of buffering in OCaml. In fact, I remember having the same problem when dabbling in OCaml a while back. I distinctly remember reading this:
The strange order of code execution in OCaml
and I'm almost certain that adding "%!" worked. I've even tried
Out_channel.flush stdout
between the two printf's, and it doesn't work. I've tried adding a "\n" in the first printf. And I've tried this in a couple of terminals.
I'm sure it's something really trivial, possibly just basic syntax.

You defined getline as a variable, not a function.
A function must always accept one parameter, although that parameter can be ():
open Stdio
let getline () =
match In_channel.input_line In_channel.stdin with
| Some x -> x
| None -> "No input"
;;
let () =
printf "What's your name? ";
printf "Hi, %s!" (getline ());;

Related

Create list from input using interact in Haskell

I'm starting out with Haskell and was looking into I/O mechanims. I read up on the interact function which takes a function of type String -> String as parameter. I tried to write a simple program that takes to numbers from stdin and creates a list and prints it line by line.
import Data.List
readIn = sort . map read . words
writeOut = unlines . map show
rangeList [n,m] = [n .. m]
main = interact (writeOut . rangeList . readIn)
For some reason it wont print the numbers. Could you help me out?
interact requires you to input an end-of-file (EOF) to stdin with Ctrl+D (or Ctrl+Z on Windows); when I type that combination, the output appears as required. This is necessary because, as the documentation for interact states, ‘the entire input from the standard input device is passed to [interact] as its argument’; due to this, you need to explicitly signal the place where stdin ends.
(By the way, I’m not even sure how you got your program to compile; GHC gives me lots of ‘ambiguous type’ errors when I try. I had to add type signatures to get it working, at which point I found the solution above to work.)

How to use scanf in OCaml

I'm trying to make something like the following:
x = scanf(stdin);
But it has to be in OCaml, I've been reading but I can't seem to find a proper way to do this, what I'm doing is a card game and in the beginning I want to ask the user of the game, through the terminal, the amount of players that are going to play and that's why I need to scan from standard in. Thank you very much in advance.
For such a simple task, scanf is probably overkill. You might want to use read_int to get started.
# read_int ();;
17
- : int = 17
(The second line here is typed by the user, i.e., me.)
You don't have to specify stdin, do something like:
print_string "Enter number of players: ";
let p = scanf "%d" (fun x:int -> x) in
print_int p;
print_newline()

OCaml string length limitation when reading from stdin\file

As part of a Compiler Principles course I'm taking in my university, we're writing a compiler that's implemented in OCaml, which compiles Scheme code into CISC-like assembly (which is just C macros).
the basic operation of the compiler is such:
Read a *.scm file and convert it to an OCaml string.
Parse the string and perform various analyses.
Run a code generator on the AST output from the semantic analyzer, that outputs text into a *.c file.
Compile that file with GCC and run it in the terminal.
Well, all is good and well, except for this: I'm trying to read an input file, that's around 4000 lines long, and is basically one huge expressions that's a mix of Scheme if & and.
I'm executing the compiler via utop. When I try to read the input file, I immediately get a stack overflow error message. It is my initial guess that the file is just to large for OCaml to handle, but I wasn't able to find any documentation that would support this theory.
Any suggestions?
The maximum string length is given by Sys.max_string_length. For a 32-bit system, it's quite short: 16777211. For a 64-bit system, it's 144115188075855863.
Unless you're using a 32-bit system, and your 4000-line file is over 16MB, I don't think you're hitting the string length limit.
A stack overflow is not what you'd expect to see when a string is too long.
It's more likely that you have infinite recursion, or possibly just a very deeply nested computation.
Well, it turns out that the limitation was the amount of maximum ram the OCaml is configured to use.
I ran the following command in the terminal in order to increase the quota:
export OCAMLRUNPARAM="l=5555555555"
This worked like a charm - I managed to read and compile the input file almost instantaneously.
For reference purposes, this is the code that reads the file:
let file_to_string input_file =
let in_channel = open_in input_file in
let rec run () =
try
let ch = input_char in_channel in ch :: (run ())
with End_of_file ->
( close_in in_channel;
[] )
in list_to_string (run ());;
where list_to_string is:
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;;
funny thing is - I wrote file_to_string in tail recursion. This prevented the stack overflow, but for some reason went into an infinite loop. Oh, well...

Haskell: odd difference between compiled vs interpreted functions which print concatenated infinite lists

I'm just exploring Haskell for fun, and to learn about the language. I thought the following behavior was interesting, and I can't find the reason why this happens.
This is an often quoted piece of Haskell code which keeps calculating pi until interrupted, slightly modified to give a concatenated list of chars instead of a list of integers:
main :: IO ()
main = do putStrLn pi'
pi' :: [Char]
pi' = concat . map show $ g(1,0,1,1,3,3) where
g(q,r,t,k,n,l) =
if 4*q+r-t<n*t
then n : g(10*q,10*(r-n*t),t,k,div(10*(3*q+r))t-10*n,l)
else g(q*k,(2*q+r)*l,t*l,k+1,div(q*(7*k+2)+r*l)(t*l),l+2)
If I run it from prelude, it starts concatenating a string resembling the digits of pi:
λ> putStrLn pi'
31415926535897932384626433832795028841971 ...etc
Works as expected, it instantly starts spewing out digits.
Now this is a piece of code I just quickly wrote which has the same structure. It's completely useless from a mathematical point of view, I was just messing around to find out how Haskell works. The operations are much simpler, but it does have the same type, and so does the sub function (except for the smaller tuple).
main :: IO ()
main = do putStrLn func
func :: [Char]
func = concat . map show $ h(1,2,1) where
h(a,b,c) =
if a <= 1000
then a : h((div a 1)+2*b,b,1)
else h(b,div (b-3) (-1),div a a)
Same type of result from prelude:
λ> putStrLn func
1591317212529333741454953576165697377818589 ...etc
Works as expected, although much faster than the pi function of course, because the calculations are less complex.
Now for the part which confuses me:
If I compile: ghc pi.hs, and run my program: ./pi, the output stays blank forever, until I send an interrupt signal. At that moment, the whole calculated string of pi is instantly displayed. It doesn't "stream" the output into stdout, like GHCI does. OK, I know they don't always behave in the same way.
But next I run: ghc func.hs, and run my program: ./func... and it immediately starts printing the list of characters.
Where does this difference come from? I thought it might be because my stupid useless little function is (eventually) repeating, so the compiler can "predict" the output better?
Or is there another fundamental difference between the way the functions work? Or am I doing something utterly stupid?
Solution / Answer
Provided by Thomas & Daniel below, I was:
Impatient. Large chunks eventually show up with the pi function, it's just a bit slow on my simple old coding machine.
Not handling buffering in any way.
So after rewriting the main function:
import System.IO
main :: IO ()
main = do hSetBuffering stdout NoBuffering
putStrLn pi'
It was fixed!
Provided by Thomas & Daniel in the comments, it turned out I was:
Impatient. Large chunks eventually show up with the pi function, it's just a bit slow on my simple old coding machine.
Not handling buffering in any way.
So after rewriting the main function:
import System.IO
main :: IO ()
main = do hSetBuffering stdout NoBuffering
putStrLn pi'
It was fixed!

OCaml lex: doesn't work at all, whatsoever

I am at the end of my rope here. I cannot get anything to work in ocamllex, and it is driving me nuts. This is my .mll file:
{
open Parser
}
rule next = parse
| (['a'-'z'] ['a'-'z']*) as id { Identifier id }
| '=' { EqualsSign }
| ';' { Semicolon }
| '\n' | ' ' { next lexbuf }
| eof { EOF }
Here are the contents of the file I pass in as input:
a=b;
Yet, when I compile and run the thing, I get an error on the very first character, saying it's not valid. I honestly have no idea what's going on, and Google has not helped me at all. How can this even be possible? As you can see, I'm really stumped here.
EDIT:
I was working for so long that I gave up on the parser. Now this is the relevant code in my main file:
let parse_file filename =
let l = Lexing.from_channel (open_in filename) in
try
Lexer.next l; ()
with
| Failure msg ->
printf "line: %d, col: %d\n" l.lex_curr_p.pos_lnum l.lex_curr_p.pos_cnum
Prints out "line: 1, col: 1".
Without the corresponding ocamlyacc parser, nobody will be able to find the issue with your code since your lexer works perfectly fine!
I have taken the liberty of writing the following tiny parser (parser.mly) that constructs a list of identifier pairs, e.g. input "a=b;" should give the singleton list [("a", "b")].
%{%}
%token <string> Identifier
%token EqualsSign
%token Semicolon
%token EOF
%start start
%type <(string * string) list> start
%%
start:
| EOF {[]}
| Identifier EqualsSign Identifier Semicolon start {($1, $3) :: $5}
;
%%
To test whether the parser does what I promised, we create another file (main.ml) that parses the string "a=b;" and prints the result.
let print_list = List.iter (fun (a, b) -> Printf.printf "%s = %s;\n" a b)
let () = print_list (Parser.start Lexer.next (Lexing.from_string "a=b;"))
The code should compile (e.g. ocamlbuild main.byte) without any complaints and the program should output "a=b;" as promised.
In response to the latest edit:
In general, I don't believe that catching standard library exceptions that are meant to indicate failure or misuse (like Invalid_argument or Failure) is a good idea. The reason is that they are used ubiquitously throughout the library such that you usually cannot tell which function raised the exception and why it did so.
Furthermore, you are throwing away the only useful information: the error message! The error message should tell you what the source of the problem is (my best guess is an IO-related issue). Thus, you should either print the error message or let the exception propagate to the toplevel. Personally, I prefer the latter option.
However, you probably still want to deal with syntactically ill-formed inputs in a graceful manner. For this, you can define a new exception in the lexer and add a default case that catches invalid tokens.
{
exception Unexpected_token
}
...
| _ {raise Unexpected_token}
Now, you can catch the newly defined exception in your main file and, unlike before, the exception is specific to syntactically invalid inputs. Consequently, you know both the source and the cause of the exception giving you the chance to do something far more meaningful than before.
A fairly random OCaml development hint: If you compile the program with debug information enabled, setting the environment variable OCAMLRUNPARAM to "b" (e.g. export OCAMLRUNPARAM=b) enables stack traces for uncaught exceptions!
btw. ocamllex also can do the + operator for 'one or more' in regular expressions, so this
['a'-'z']+
is equivalent to your
['a'-'z']['a'-'z']*
I was just struggling with the same thing (which is how I found this question), only to finally realize that I had mistakenly specified the path to input file as Sys.argv.(0) instead of Sys.argv.(1)! LOLs
I really hope it helps! :)
It looks like you have a space in the regular expression for identifiers. This could keep the lexer from recognizing a=b, although it should still recognize a = b ;