为什么我得到警告这个表达式应该有这个代码的类型单元?尽管它做了它应该做的事。
let matchInf42 list =
let a = ref 0 in
let lstLength = List.length list in
let rec matchInf4242 list =
match list with
|[]->[]
|m::body->
begin
if (m < 42) then a := !a + 1;
matchInf4242 body
end
in matchInf4242 list;
if(!a = lstLength) then -1 else 0
警告:
ocamlopt match.ml -o m
File "match.ml", line 14, characters 7-24:
14 | in matchInf4242 list;
^^^^^^^^^^^^^^^^^
Warning 10: this expression should have type unit.
TL;DR:您获得的错误是典型类型的错误(大部分(
"大部分";因为,无可否认,它不是一个";错误";而仅仅是";警告";然而,在这里,这种警告(警告10:非单位语句(似乎总是值得解决(即避免(。
它实际上是以下模式的一个实例:
42; print_string "…" ;;
(* or more generally *)
any_value_not_having_type_unit; any_value_having_type_unit ;;
(* which would raise *)
> Characters 0-2:
> 42; print_string "…";;
> ^^
> Warning 10: this expression should have type unit.
> …- : unit = ()
更多详细信息
回想一下,unit
是一个单例类型(它只有值()
(,并且通常被选择为将返回类型分配给"0"的函数;不返回特定值";但会产生一些副作用。
实际上,序列运算符是";更通用/更灵活";正如我们所期望的:
# let semicolon i j = i; j ;;
val semicolon : 'a -> 'b -> 'b = <fun>
也就是说,它是而不是semicolon : unit -> 'b -> 'b
,因此,当i
不具有类型unit
时,我们为代码i; j
得到的消息只是一个警告,而不是类型错误。
修复/解决方案
避免此警告的两种策略:
通过依赖
ignore
函数忽略它# ignore;; - : 'a -> unit = <fun> # ignore 42; print_string "…";; …- : unit = ()
或者更改/修复计算序列左侧的方式(因此其类型为
unit
(。在你的问题示例的特定情况下,写下以下内容就足够了(唯一的变化用符号
§
表示(:let matchInf42 list = let a = ref 0 in let lstLength = List.length list in let rec matchInf4242 list = match list with |[] -> () (*←§*) |m::body-> begin if (m < 42) then a := !a + 1; matchInf4242 body end in matchInf4242 list; if(!a = lstLength) then -1 else 0
额外备注
最后,为了完整性(尽管这不是你问题的明确部分(,请注意,你考虑的示例函数也可以用更";"功能性";样式(没有引用也没有序列,也避免了预先调用List.length
函数的需要(:
let matchInf42 l =
if List.for_all (fun m -> m < 42) l
then -1 else 0
(* or *)
let matchInf42 l =
if List.fold_left (fun r e -> r && e < 42) true l
then -1 else 0
将matchInf4242 list
更改为ignore (matchInf4242 list)
或matchInf4242 list in ()
。
这使得语句返回()
(即一个单元(,这正是ocaml所期望的。