I’m currently trying to learn OCaml via the "Real World OCaml: Functional Programming for the Masses" textbook. I’ve reached the point of trying to build my first executable after playing inside utop, but the program keeps crashing in the following manner. The code itself is the exact same from the book:
open Base
open Stdio
let rec read_and_accumulate accum =
let line = In_channel.input_line In_channel.stdin in
match line with
| None -> accum
| Some x -> read_and_accumulate (accum +. Float.of_string x)
let () =
printf "Total: %Fn" (read_and_accumulate 0.)
And the error log after trying to build it with dune and running gives
Fatal error: exception Invalid_argument("Float.of_string ")
Raised at Stdlib.invalid_arg in file "stdlib.ml", line 30, characters 20-45
Called from Dune__exe__Main.read_and_accumulate in file "bin/main.ml", line 8, characters 44-61
Called from Dune__exe__Main in file "bin/main.ml", line 11, characters 23-47
I’ll admit that I’m not too sure why Float.of_string
seems to be the cause of the problem here, as it works just fine inside utop when I test it.
I should add that I’m running OCaml version 4.13.1 on Debian and that both Base and Stdio are installed. I can also add the screenshot below for clarification:
2
Answers
As mentioned in the comments, the correct way to end the program was via
Ctrl-D
instead of hittingEnter
twice, my bad.As you’ve noted, the issue is with the input you provided. Rather than providing an EOF (end-of-file) signal, you’ve entered a blank line. We can readily see that this causes an exception.
The basic solution is very simple: press Ctrl-D to send the EOF signal. However, we can look at alternate ways to handle this exception which may be instructive.
Note: only standard library modules and functions used in the following.
You can handle the exception and use that to terminate the recursion.
You could also skip that "faulty" input.
You might also extract the process of reading input and getting a sum of the float values:
This function will read in a list of lines which we could then process using
List
module functions.You might rightly say that generating a list isn’t strictly required, and you’d be right, so OCaml provides a module for lazy sequences:
Seq
.