Ведомственные ограничения против unsafePerformIO - PullRequest
6 голосов
/ 08 октября 2010

Ходили разговоры о том, чтобы сделать это общепринятой политикой, запрещающей использование unsafePerformIO и тому подобное. Лично я не против, потому что всегда утверждал, что если я захочу его использовать, это обычно означает, что мне нужно переосмыслить свой подход.

Это ограничение звучит разумно? Кажется, я помню, что читал где-то, что это было включено в основном для FFI, но я не могу вспомнить, где я читал это в данный момент.

редактировать: Хорошо, это моя вина. Это не будет ограничено там, где это разумно необходимо, т.е. FFI. Смысл политики заключается в том, чтобы не допустить лени и запахов кода.

Ответы [ 5 ]

13 голосов
/ 08 октября 2010

Многие основные библиотеки, такие как ByteString, используют unsafePerformIO под капотом, например, для настройки выделения памяти.

Когда вы используете такую ​​библиотеку, вы полагаете, что автор библиотеки доказал ссылочную прозрачность своего экспортируемого API и что все необходимые предварительные условия для пользователя задокументированы. Вместо полного запрета вашему департаменту следует разработать политику и процесс проверки для получения аналогичных гарантий внутри страны.

12 голосов
/ 08 октября 2010

Ну, есть допустимых значений unsafePerformIO. Это не просто чтобы быть декоративным или соблазном проверить свою добродетель. Однако ни одно из этих применений не предполагает добавления значимых побочных эффектов в повседневный код. Вот несколько примеров использования, которые могут потенциально быть оправданными, с различными степенями подозрения:

  • Обертывание функции, которая является нечистой внутри, но не имеет внешних видимых побочных эффектов. Это та же самая основная идея, что и у монады ST, за исключением того, что здесь бремя, лежащее на программисте, состоит в том, чтобы показать, что примесь не «протекает».

  • Маскировка функции, которая намеренно нечистой, каким-то ограниченным способом. Например, примесь только для записи выглядит так же, как и общая чистота «изнутри», поскольку нет способа наблюдать за полученным результатом. Это может быть полезно для некоторых видов журналирования или отладки, когда вы явно не хотите согласованности и четкого порядка, требуемого монадой IO. Примером этого является Debug.Trace.trace, который я иногда называю unsafePerformPrintfDebugging.

  • Самоанализ на чистых вычислениях, дающий чистый результат. Классическим примером является что-то вроде оператора однозначного выбора , который может параллельно запускать две эквивалентные чистые функции, чтобы быстрее получить ответ.

  • Внутренне ненаблюдаемое нарушение ссылочной прозрачности, такое как введение недетерминизма при инициализации данных. Пока каждая нечистая функция оценивается только один раз, ссылочная прозрачность будет эффективно сохраняться во время любого отдельного запуска программы, даже если одна и та же искусственно-чистая функция, вызываемая с одинаковыми аргументами, дает разные результаты при разных запусках.

Важно отметить, что все вышеперечисленное заключается в том, что получаемая примесь тщательно контролируется и имеет ограниченную область применения. Учитывая более мелкозернистую систему контроля побочных эффектов, чем универсальная монада IO, все они были бы очевидными кандидатами для отсечения кусочков пол чистоты, во многом как контролируемое изменяемое состояние в вышеупомянутой монаде ST. .


Post scriptum: Если рассматривается жесткая позиция против любого необязательного использования unsafePerformIO, я решительно поощряю расширение запрета для включения unsafeInterleaveIO и любых функций, позволяющих наблюдать за его поведением. Это по крайней мере так же схематично, как некоторые из unsafePerformIO примеров, которые я перечислил выше, если вы спросите меня.

7 голосов
/ 09 октября 2010

unsafePerformIO - это запуск монады ввода-вывода. Это иногда необходимо. Однако, в отличие от runST, компилятор не может проверить, сохраняете ли вы ссылочную прозрачность.

Так что, если вы используете его, программист должен объяснить, почему его использование безопасно. Это не должно быть запрещено, оно должно сопровождаться доказательствами.

4 голосов
/ 14 октября 2010

Outlawing unsafePerformIO в коде "приложения" - отличная идея.На мой взгляд, нет оправдания для unsafePerformIO в обычном коде, и по моему опыту это не нужно.Это на самом деле не часть языка, так что вы больше не программируете на Haskell, если используете его.Откуда вы знаете, что это вообще означает?

С другой стороны, использование unsafePerformIO в привязке FFI целесообразно, если вы знаете, что делаете.

3 голосов
/ 09 октября 2010

Изъятие unsafePerformIO - ужасная идея, потому что оно эффективно блокирует код в монаде ввода-вывода: например, привязка библиотеки ac почти всегда будет в монаде ввода-вывода - однако, используя unsafePerformIO, можно создать чисто функциональную библиотеку более высокого уровня.вершина этого.

Возможно, unsafePerformIO отражает компромисс между моделью персонального компьютера с высокой степенью состояния и чистой моделью haskell без сохранения состояния;даже вызов функции является состоянием с точки зрения компьютера, так как для этого требуется помещать аргументы в стек, связываться с регистрами и т. д., но использование основано на знании того, что эти операции на самом деле составляют функционально.

...