如何使用类型推断在类型化语言中处理未使用的返回值?

How are unused returned values handled in typed languages with type inference?

具有类型推断的强类型语言如何处理未使用的返回值(预期类型是什么并不明显)?

这是一个发生在未类型化 Python 中的示例,当然不会被捕获:

list(map(lambda item: item.some_method, some_collection))

这里 item.some_method 是为了它的副作用而被调用的,所以正确的行是:

list(map(lambda item: item.some_method(), some_collection))

没有额外的约束,具有类型推断的强类型语言通常不会阻止第一个示例,因为它在技术上是有效的,正如您所指出的那样。有几种方法可以避免这种情况。

  1. 您可以显式注释地图的类型(或在强制类型等于某物的地方使用它)。如果使用了错误的变体,这将导致类型检查错误。
  2. 一些语言(例如 Rust)区分 mapfor_each,后者应该是 impure/effectful。如果在第一个示例中使用 for_each,编译将失败,因为 lambda item: item.some_method 的类型是 A -> () -> (),而不是 A -> ()。但是,没有什么可以阻止您在这里使用 map
  3. 一些语言(例如 Haskell)区分 impure/effectful 值和 pure/effectless 值。在此设置中,map 应采用纯 lambda(使 lambda item: item.some_method() 无效),而 for_each 应采用不纯的 lambda(使 lambda item: item.some_method 无效的)。这是使用 monads 强制执行的,它充当一个标记,告诉类型系统一个值是不纯的(例如,类型 IO(A) 代表一个有效的 A 类型)。
  4. 一些语言(例如 Rust)允许跟踪值的使用和注释函数以强制它们的 return 值以某种方式成为 "used"。如果 map 以这种方式注释 #[must_use],则必须使用其 return 值,这会提醒您 lambda item: item.some_method 的不正确使用(因为 return map 的值将不会被使用)。在 Rust 中,单元类型 () 自动为 "used",理论上这可以扩展为包括 [()],在这种情况下正确的代码 lambda item: item.some_method() 可以正常工作。