【问题标题】:Ignore a function in OCaml elegantly优雅地忽略 OCaml 中的函数
【发布时间】:2017-08-14 10:53:32
【问题描述】:

我在 OCaml 4.04 版的 utop 中定义了一个函数 f。

utop # let f = function x -> x + 1;;

val f : int -> int = <fun> 

当我尝试忽略 f 时,我遇到了警告。

utop # let a = ignore (f : int -> int); f 2;;

Characters 15-19:                                             
Warning 5: this function application is partial,
maybe some arguments are missing
val a : int = 3

警告 5 被触发是因为ignore 后面的表达式有一个函数接口int -&gt; int

ignore (f 0)if false then (ignore f 0) 可以工作,但它们并不优雅。我不想为 f 提供缺失的参数。 ignore 有什么替代品吗?

ignore 的动机在这个虚拟示例中不是很清楚,但我确实需要使用它来避免在我的实际项目中出现其他警告。

感谢您的宝贵时间。

【问题讨论】:

  • 我闻到了 XY 问题 (xyproblem.info)。你能解释一下真实的用例吗?
  • 如果你不调用这个函数,你为什么还要把它放在首位?
  • 真正的用例是使用ocaml_plugin在运行时编译一些OCaml代码。这段代码可能会或可能不会调用f。鉴于我不想将f 作为我的插件的库,最好的方法是将代码附加到f 的定义中。如果不调用f,编译器会报错。

标签: ocaml


【解决方案1】:

对于e1; e2 形式的表达非常粗略地说,OCaml 类型检查器处理如下:

  • 如果 e1 的函数类型为 t -&gt; t',则会发出警告 5。
  • 否则,如果 e1 没有类型 unit,则会发出警告 10。

例如,

let f x = 
    prerr_endline "some side effect you may want"; 
    (* but you may not want the returned function sometimes *)
    fun y -> x + y

let a = f 1 2; f 1 2;;       (* Warning 10 *)
let a = f 1; f 1 2;;         (* Warning 5 *)

ignore e1; e2 的类型检查与e1; e2 的类型检查相同,除了一点:它跳过第二次检查:即使e1 的类型不是unit,也不会发出警告10。警告 5 的第一次检查仍在执行:

let a = ignore (f 1 2); f 1 2;;  (* No warning *)
let a = ignore (f 1); f 1 2;;    (* Warning 5 *)

所以 ignore 旨在删除警告 10,而不是 5。ignore 的这种特殊处理是围绕 OCaml 源代码中 typing/typecore.mlis_ignore 函数定义编码的。

如果你真的想忽略Warning 5,我想到了2个方法:

let a = let _ = f 1 in f 1 2;;   (* No warning *)

let ignore' _ = ()
let a = ignore' (f 1); f 1 2;;   (* No warning *)

第一个是使用与通配符匹配的模式。另一种是定义自己的忽略函数ignore'。这是一个常用的 OCaml 函数,因此不会对发出上述警告 5 的 ignore 的参数进行特殊类型检查。

【讨论】:

  • 如果我不想为 f 提供缺少的参数怎么办?它在这个虚拟示例中运行良好,但有时缺少的参数可能难以构造,f 可能会引发一些不正确参数的异常。
  • 我明白你的观点,如果ignore 后面跟着一个函数接口的变量,编译器总是会抱怨。我想知道ignore 是否有其他选择。谢谢!
【解决方案2】:

您可以通过将 ignore 调用替换为 let _ 构造来避免警告:

let a = let _ = (f : int -> int) in f 2;;

【讨论】:

    【解决方案3】:

    您可以定义自己的忽略函数,该函数对箭头类型进行操作,如下所示:

    let ignore_fun (f:'a -> 'b) = ()
    

    这样您就不再需要将参数传递给 f 并且以下内容不会产生警告。

    let a = ignore_fun (f : int -> int); f 2;;
    

    【讨论】:

    • 警告 27:未使用的变量 f。变量 f 未在 ignore_fun 中使用,因此触发了警告 27。
    • 我本可以写成let ignore_fun (_:'a -&gt; 'b) = () ,但我觉得不太清楚
    【解决方案4】:

    camlspotter 的回答很好,你应该接受它。 我只想添加第三种解决方案:将违规函数包装成一个元组

    let a = ignore (f,()); f 2;;
    

    或列表

    let a = ignore [f]; f 2;;
    

    或任何你喜欢的东西。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-12-02
      • 2010-10-19
      • 1970-01-01
      • 2017-07-11
      • 2014-05-31
      • 2016-05-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多