删除警告此表达式在 Ocaml 中应具有类型单元
Remove Warning this expression should have type unit in 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: 您得到的错误是典型的类型错误(大部分)
“大部分”是因为,诚然,这不是“错误”,而只是这里的“警告”,但似乎这种警告 (Warning 10: non-unit-statement) 总是值得解决(即,避免).
它实际上是以下模式的一个实例:
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
是单例类型(只有值 ()
),通常选择将 return 类型分配给“return 没有特定值”,但会产生一些副作用。
实际上,序列运算符正如我们所期望的那样“更通用/更灵活”:
# let semicolon i j = i; j ;;
val semicolon : 'a -> 'b -> 'b = <fun>
也就是说,它 不是 semicolon : unit -> 'b -> 'b
,因此当 i
不是时,我们得到的代码 i; j
的消息具有类型 unit
,只是一个警告,而不是类型错误。
Fixes/workarounds
避免此警告的两种策略:
要么忽略,靠ignore
函数
# ignore;;
- : 'a -> unit = <fun>
# ignore 42; print_string "…";;
…- : unit = ()
或change/fix计算序列左侧的方式(因此其类型为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 ()
.
这使得声明 return ()
(即一个单元),这是 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: 您得到的错误是典型的类型错误(大部分)
“大部分”是因为,诚然,这不是“错误”,而只是这里的“警告”,但似乎这种警告 (Warning 10: non-unit-statement) 总是值得解决(即,避免).
它实际上是以下模式的一个实例:
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
是单例类型(只有值 ()
),通常选择将 return 类型分配给“return 没有特定值”,但会产生一些副作用。
实际上,序列运算符正如我们所期望的那样“更通用/更灵活”:
# let semicolon i j = i; j ;;
val semicolon : 'a -> 'b -> 'b = <fun>
也就是说,它 不是 semicolon : unit -> 'b -> 'b
,因此当 i
不是时,我们得到的代码 i; j
的消息具有类型 unit
,只是一个警告,而不是类型错误。
Fixes/workarounds
避免此警告的两种策略:
要么忽略,靠
ignore
函数# ignore;; - : 'a -> unit = <fun> # ignore 42; print_string "…";; …- : unit = ()
或change/fix计算序列左侧的方式(因此其类型为
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 ()
.
这使得声明 return ()
(即一个单元),这是 ocaml 所期望的。