如何强制开始ocaml中的下一个表达式
how to force to start next expression in ocaml
我想编写一个函数来实现 grep 的基本用法:匹配文件中的模式。我想 match_file_pattern 到 return 匹配行列表。但是这里的代码无法编译,错误是:
Error: This expression has type string list
but an expression was expected of type unit
代码是:
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
之间关系的方法,但失败了。
循环的类型是 unit
,即使它从未完成。类型检查器不知道这一点,因此您需要使 try
下的表达式与异常处理程序具有相同的类型。
在这种情况下,您可以使用任意列表,例如 []
,但它对 reader 具有误导性,并且不会泛化到提供表达式可能更复杂的情况正确的类型。
这里惯用的解决方案是放置一个 assert false
,如果计算过,它会引发异常。与无限 while
循环不同,类型检查器知道 assert false
不是 return 并且它与任何类型兼容,因为永远不会产生值:
try
while true do
...
done;
assert false
with ... -> ...
您可以使用 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
您的代码很好:
done
后一个分号,用于指令排序,然后!matched_lines
作为try代码部分的return值,然后with ...
.
这里没有歧义。编译器只是没有考虑到 End_of_file
总是被引发。
剩下的就是编码风格的问题了。我喜欢在这些技术上需要的表达式上添加 (* never reached *)
评论 - 这对于 assert false
提案以及 IMO 来说都是一个好主意。
我想编写一个函数来实现 grep 的基本用法:匹配文件中的模式。我想 match_file_pattern 到 return 匹配行列表。但是这里的代码无法编译,错误是:
Error: This expression has type string list but an expression was expected of type unit
代码是:
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
之间关系的方法,但失败了。
循环的类型是 unit
,即使它从未完成。类型检查器不知道这一点,因此您需要使 try
下的表达式与异常处理程序具有相同的类型。
在这种情况下,您可以使用任意列表,例如 []
,但它对 reader 具有误导性,并且不会泛化到提供表达式可能更复杂的情况正确的类型。
这里惯用的解决方案是放置一个 assert false
,如果计算过,它会引发异常。与无限 while
循环不同,类型检查器知道 assert false
不是 return 并且它与任何类型兼容,因为永远不会产生值:
try while true do ... done; assert false with ... -> ...
您可以使用 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
您的代码很好:
done
后一个分号,用于指令排序,然后!matched_lines
作为try代码部分的return值,然后with ...
.
这里没有歧义。编译器只是没有考虑到 End_of_file
总是被引发。
剩下的就是编码风格的问题了。我喜欢在这些技术上需要的表达式上添加 (* never reached *)
评论 - 这对于 assert false
提案以及 IMO 来说都是一个好主意。