Ведомственные ограничения против unsafePerformIO
На работе ведутся разговоры о том, чтобы сделать это общеотраслевой политикой, запрещающей использование unsafePerformIO
и тому подобное. Лично я не против, потому что всегда утверждал, что если я захочу его использовать, это обычно означает, что мне нужно переосмыслить свой подход.
Это ограничение звучит разумно? Кажется, я помню, что читал где-то, что это было включено в основном для FFI, но я не могу вспомнить, где я читал это в данный момент.
редактировать: хорошо, это моя вина. Это не будет ограничено там, где это разумно необходимо, т.е. FFI. Смысл политики заключается в том, чтобы больше препятствовать лени и запахам кода.
5 ответов
Многие основные библиотеки, такие как ByteString
использование unsafePerformIO
под капотом, например, для настройки выделения памяти.
Когда вы используете такую библиотеку, вы доверяете, что автор библиотеки доказал ссылочную прозрачность их экспортированного API, и что все необходимые предварительные условия для пользователя задокументированы. Вместо полного запрета вашему департаменту следует разработать политику и процесс проверки для получения аналогичных гарантий внутри страны.
Ну, есть действительные применения для unsafePerformIO
, Это не просто чтобы быть декоративным или соблазном проверить свою добродетель. Однако ни одно из этих применений не предполагает добавления значимых побочных эффектов в повседневный код. Вот несколько примеров использования, которые потенциально могут быть оправданы с различной степенью подозрения:
Обертывание функции, которая является нечистой внутри, но не имеет внешних видимых побочных эффектов. Это та же основная идея, что и
ST
Монада, за исключением того, что здесь бремя для программиста показать, что примесь не "протекает".Маскировка функции, которая намеренно нечистой, каким-то ограниченным способом. Например, примесь только для записи выглядит так же, как и общая чистота "изнутри", поскольку нет способа наблюдать за полученным результатом. Это может быть полезно для некоторых видов ведения журнала или отладки, когда вы явно не хотите согласованности и четкого порядка, требуемого
IO
монада. Примером этого являетсяDebug.Trace.trace
, который я иногда называюunsafePerformPrintfDebugging
,Самоанализ на чистых вычислениях, производящий чистый результат. Классическим примером является что-то вроде оператора однозначного выбора, который может параллельно запускать две эквивалентные чистые функции, чтобы быстрее получить ответ.
Внутренне ненаблюдаемое нарушение ссылочной прозрачности, такое как введение недетерминизма при инициализации данных. До тех пор, пока каждая нечистая функция оценивается только один раз, ссылочная прозрачность будет эффективно сохраняться во время любого отдельного запуска программы, даже если одна и та же искусственно-чистая функция, вызываемая с одинаковыми аргументами, дает разные результаты при разных запусках.
Важно отметить, что все вышеперечисленные примеси тщательно контролируются и ограничены в объеме. Учитывая более мелкозернистую систему контроля побочных эффектов, чем универсальные IO
Монада, все они были бы очевидными кандидатами на обрезание кусочков полупрозрачности, во многом как контролируемое изменяемое состояние в вышеупомянутом ST
монада.
Post scriptum: если жесткая позиция против любого необязательного использования unsafePerformIO
рассматривается, я настоятельно рекомендую расширить запрет на включение unsafeInterleaveIO
и любые функции, которые позволяют наблюдать за его поведением. Это по крайней мере так же схематично, как некоторые из unsafePerformIO
примеры, которые я перечислил выше, если вы спросите меня.
unsafePerformIO - это запуск монады ввода-вывода. Это иногда необходимо. Однако, в отличие от runST, компилятор не может проверить, сохраняете ли вы ссылочную прозрачность.
Поэтому, если вы используете его, у программиста есть бремя, чтобы объяснить, почему его использование безопасно. Это не должно быть запрещено, оно должно сопровождаться доказательствами.
Объявление вне закона unsafePerformIO
в "приложении" код это отличная идея. На мой взгляд, нет оправдания unsafePerformIO
в нормальном коде и по моему опыту это не нужно. Это на самом деле не часть языка, так что вы больше не программируете на Haskell, если используете его. Откуда ты знаешь, что это вообще значит?
С другой стороны, используя unsafePerformIO
в FFI обязательна привязка, если вы знаете, что делаете.
Изъятие unsafePerformIO - ужасная идея, потому что оно эффективно блокирует код в монаде ввода-вывода: например, привязка библиотеки ac почти всегда будет в монаде ввода-вывода - однако, используя unsafePerformIO, можно построить чисто функциональную библиотеку более высокого уровня.,
Возможно, unsafePerformIO отражает компромисс между моделью персонального компьютера с высокой степенью состояния и чистой моделью haskell без учета состояния; даже вызов функции является состоянием с точки зрения компьютера, так как он требует помещения аргументов в стек, работы с регистрами и т. д., но использование основано на знании того, что эти операции фактически составляют функционально.