Как обрабатываются неиспользуемые возвращаемые значения в типизированных языках с выводом типа? - PullRequest
0 голосов
/ 09 марта 2020

Как языки со строгой типизацией, имеющие вывод типа, обрабатывают неиспользуемые возвращаемые значения (где неясно, что представляет собой предполагаемый тип)?

Вот пример, где это происходит в нетипизированном Python, где оно, конечно, не перехвачено:

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

Здесь item.some_method должен был быть вызван, для его побочных эффектов, поэтому правильная строка:

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

1 Ответ

1 голос
/ 27 марта 2020

Без дополнительных ограничений язык со строгой типизацией с выводом типа, как правило, не помешает первому примеру, поскольку он технически обоснован, как вы указали. Этого можно избежать несколькими способами.

  1. Вы можете явно аннотировать тип карты (или использовать его где-нибудь, чтобы тип был чем-то равен). Это может привести к ошибке проверки типа, если используется неправильный вариант.
  2. Некоторые языки (например, Rust) различают guish между map и for_each, где последний ожидается нечистый / effectful. Если вы используете for_each в первом примере, компиляция будет невозможна, так как тип lambda item: item.some_method равен A -> () -> (), а не A -> (). Однако ничто не мешает вам однозначно использовать map здесь.
  3. Некоторые языки (например, Haskell) различают guish между нечистыми / эффективными значениями и чистыми / неэффективными значениями. В этом случае ожидается, что map будет принимать чистую лямбду (делает lambda item: item.some_method() недействительным), а for_each будет принимать лямбду, которая является нечистой (делает lambda item: item.some_method недействительным). Это выполняется с использованием монад , которые действуют как маркер, который сообщает системе типов, что значение нечисто (например, тип IO(A) представляет эффективный тип A).
  4. Некоторые языки (например, Rust) позволяет отслеживать использование значений и аннотировать функции, чтобы заставить их возвращаемые значения каким-либо образом «использоваться». Если map аннотируется #[must_use] таким образом, то должно использоваться его возвращаемое значение, которое предупредит вас о неправильном использовании lambda item: item.some_method (так как возвращаемое значение map не будет использоваться). В Rust тип устройства () автоматически «используется», и теоретически это можно расширить, включив [()], и в этом случае правильный код lambda item: item.some_method() будет работать без проблем.
...