Reputation: 177
I want to write a function that implements basic usage of grep: matching a pattern in a file. And I want to match_file_pattern to return a list of matched lines. But the code here cannot compile, the error is:
Error: This expression has type string list but an expression was expected of type unit
And the code is:
let match_file pattern file_name =
let matched_lines = ref [] in
let ic = open_in file_name in
try
while true
do
let line = input_line ic in
if (Str.string_match (Str.regexp pattern) line 0)
then
matched_lines := line::!matched_lines
done;**(*!matched_lines*)**(*I need add this to compile successfully*)
with End_of_file ->
close_in ic;
List.rev !matched_lines;;
I think the error is caused by in ocaml
, close_in ic; List.rev !matched_lines
is grouped into a subexpression of "with" keyword, so its type should match with "try" expression. I try to find ways to break the relation between close_in ic;
and List.rev !matched_lines
, but failed.
Upvotes: 1
Views: 115
Reputation: 1439
Your code is just fine:
one semicolon after done
, for sequencing of instructions, and then !matched_lines
as return value of the try code part, then with ...
.
No ambiguities here. The compiler just doesn't take into account that End_of_file
is always raised.
The rest is question of coding style. I like putting a (* never reached *)
comment at these technically required expressions - would be a good idea for the assert false
proposal as well IMO.
Upvotes: 0
Reputation: 66823
You can use begin/end
or parentheses:
let match_file pattern file_name =
let matched_lines = ref [] in
let ic = open_in file_name in
begin
try
while true
do
let line = input_line ic in
if (Str.string_match (Str.regexp pattern) line 0)
then
matched_lines := line::!matched_lines
done
with End_of_file -> close_in ic
end;
List.rev !matched_lines
Upvotes: 2
Reputation: 4939
The type of the loop is unit
even though it never complete. The typechecker doesn't know that, so you need to make the expression under try
have the same type as the exception handlers.
In this case you could use an arbitrary list such as []
but it's misleading for the reader, and doesn't generalize to cases where it may be more complicated to provide an expression of the correct type.
The idiomatic solution here is to place an assert false
, which would raise an exception if ever evaluated. Unlike the infinite while
loop, assert false
is known by the typechecker to not return and it is compatible with any type since a value is never produced:
try while true do ... done; assert false with ... -> ...
Upvotes: 1