删除警告此表达式应在Ocaml中具有类型单位



为什么我得到警告这个表达式应该有这个代码的类型单元?尽管它做了它应该做的事。

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得到的消息只是一个警告,而不是类型错误。

修复/解决方案

避免此警告的两种策略:

  1. 通过依赖ignore函数忽略它

    # ignore;;
    - : 'a -> unit = <fun>
    # ignore 42; print_string "…";;
    …- : unit = ()
    
  2. 或者更改/修复计算序列左侧的方式(因此其类型为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所期望的。

最新更新