我想编写一个实现grep基本用法的函数:匹配文件中的模式。我想match_file_pattern返回匹配行的列表。但是这里的代码无法编译,错误是:
错误:此表达式具有类型字符串列表 但是预期表达式为单位
代码是:
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;;
我认为错误是由ocaml
引起的,close_in ic; List.rev !matched_lines
被分组为“with”关键字的子表达式,因此其类型应与“try”表达式匹配。我试图找到打破close_in ic;
和List.rev !matched_lines
之间关系的方法,但失败了。
答案 0 :(得分:2)
您可以使用begin/end
或括号:
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
答案 1 :(得分:1)
循环的类型是unit
,即使它永远不会完成。类型检查器不知道,因此您需要使try
下的表达式与异常处理程序具有相同的类型。
在这种情况下,您可以使用任意列表,例如[]
,但这会对读者产生误导,并且不会推广到提供正确类型的表达式可能更复杂的情况。
这里惯用的解决方案是放置一个assert false
,如果进行评估会引发异常。与无限while
循环不同,typechecker知道assert false
不返回,并且它与任何类型都兼容,因为永远不会产生值:
try while true do ... done; assert false with ... -> ...
答案 2 :(得分:0)
你的代码很好:
done
之后的一个分号,用于指令排序,然后!matched_lines
作为try代码部分的返回值,然后是with ...
。
这里没有含糊之处。编译器没有考虑到始终引发End_of_file
。
其余的是编码风格的问题。我喜欢对这些技术上要求的表达式发表(* never reached *)
评论 - 对于assert false
提案以及IMO也是一个好主意。