What's the proper usage for Lwt_io.read_int?

467 views Asked by At

How do you properly use Lwt_io.read_int? I tried what I thought was the obvious usage but I don't get obvious results...

open Lwt.Infix

let _ =
  Lwt_main.run
    (
      Lwt_io.print "Enter number: " >>=
      fun () -> Lwt_io.read_int (Lwt_io.stdin) >>=
      fun d -> Lwt_io.printf "%d\n" d
    )

I compiled, ran and inputed 12345 when prompted and the program displayed 875770417.

I'm missing something here...

With the help below I arrived at this. It works and I hope its correct.

open Lwt.Infix

let _ =
  Lwt_main.run
    (
      Lwt_io.print "Enter number: " >>=
      fun () -> Lwt_io.read_line (Lwt_io.stdin) >>=
      fun s -> 
      (
        try
          Lwt.return_some( Pervasives.int_of_string s)
        with
        | _ -> Lwt.return_none
      ) >>=
      fun o -> 
      Lwt_io.print
        (
          match o with
          | Some i -> Printf.sprintf "%d\n" i
          | None -> "Ooops, invalid format!\n"
        )
    )

I think I should post some code to demonstrate the proper usage of Lwt_io.read_int.

open Lwt.Infix
open Lwt_io

let _ =
  Lwt_main.run
    (
      let i, o = Lwt_io.pipe() in
      Lwt_io.write_int o 1 >>=
      fun () -> Lwt_io.flush o >>=
      fun () -> Lwt_io.close o >>=
      fun () -> Lwt_io.read_int i >>=
      fun d -> Lwt_io.printf "%d\n" d >>=
      fun () -> Lwt_io.close i
    )
2

There are 2 answers

0
Étienne Millon On BEST ANSWER

This reads a binary encoded integer, for example in order to deserialize some data from a file.

You read 875770417 which is in hex 0x34333231, which in turns corresponds to the ASCII encoding of '1', '2', '3', and '4' in little endian ordering.

You probably want to read a string using Lwt_io.read_line and convert the result using int_of_string.

0
Lhooq On

According to this page, I tried some experimentations.

First, I wrote :

open Lwt.Infix

let _ =
  Lwt_main.run
    (
      let open Lwt_io in
      print "Enter number: " >>=
        fun () -> read_line stdin >>=
      fun d -> printlf "%s" d
    )

And I got all the output I wanted.

Fine, now let's try with integers since it's written that

val read_int : Lwt_io.input_channel -> int Lwt.t

Reads a 32-bits integer as an ocaml int

open Lwt.Infix

let _ =
  Lwt_main.run
    (
      let open Lwt_io in
      print "Enter number: " >>=
        fun () -> read_int stdin >>=
      fun d -> write_int stdout d
    )

Well, strange behaviour here :

lhooq@lhooq-linux lwt_io $ ./main.native 
Enter number: 100
100
lhooq@lhooq-linux lwt_io $ ./main.native 
Enter number: 1000
1000lhooq@lhooq-linux lwt_io $ ./main.native 
Enter number: 10000
1000lhooq@lhooq-linux lwt_io $ 
lhooq@lhooq-linux lwt_io $ ./main.native 
Enter number: 10
20
10
2lhooq@lhooq-linux lwt_io $

So, it looks like three digits is the maximum that this function can handle but at least it prints the number you wrote.

Next test :

open Lwt.Infix

let _ =
  Lwt_main.run
    (
      let open Lwt_io in
      print "Enter number: " >>=
        fun () -> read_int stdin >>=
      fun d -> printlf "%d" d
    )

Exactly your problem here :

lhooq@lhooq-linux lwt_io $ ./main.native 
Enter number: 100
170930225

So let's write this :

open Lwt.Infix

let _ =
  Lwt_main.run
    (
      let open Lwt_io in
      print "Enter number: " >>=
        fun () -> read_int stdin >>=
      fun d -> eprintf "%x\n" d
    )

And test again :

lhooq@lhooq-linux lwt_io $ ./main.native 
Enter number: 100
a303031

Which is exactly "001" in ASCII.

I hope this will help you to figure out which function to use. In my humble opinion, I don't understand why reading an integer (and it's exactly the same with float64 or int64 but this time limited to 7 digits) seems so hard. I would suggest using read_line and int_of_string since at least this works well.