System.IO.Unsafe
| Авторские права | (c) The University of Glasgow 2001 |
|---|---|
| Лицензия | в стиле BSD (см. файл libraries/base/LICENSE) |
| Сопровождающий | libraries@haskell.org |
| Стабильность | предварительная |
| Переносимость | переносимая |
| Безопасный Haskell | Небезопасный |
| Язык | Haskell2010 |
Содержание
Описание
«Небезопасные» операции ввода-вывода.
Небезопасные операции IO
unsafePerformIO :: IO a -> a Источник
Это «чёрный ход» в монаду IO, позволяющий выполнять вычисление IO в любой момент. Чтобы это было безопасно, вычисление IO должно быть свободно от побочных эффектов и не зависеть от своего окружения.
Если операция ввода-вывода, обёрнутая в unsafePerformIO, выполняет побочные эффекты, то относительный порядок их выполнения (по отношению к основному потоку ввода-вывода или другим вызовам unsafePerformIO) не определён. Кроме того, используя unsafePerformIO для выполнения побочных эффектов, следует соблюдать следующие меры предосторожности, чтобы гарантировать ожидаемое количество выполнений этих эффектов. Обратите внимание, что для GHC эти меры необходимы, но могут быть недостаточны; другим компиляторам могут потребоваться иные меры предосторожности:
- Используйте
{-# NOINLINE foo #-}в качестве прагмы для любой функцииfoo, вызывающейunsafePerformIO. Если вызов будет встроен, операция ввода-вывода может выполниться более одного раза. - Используйте флаг компилятора
-fno-cse, чтобы запретить устранение общих подвыражений в модуле: оно может объединить два побочных эффекта, которые должны были оставаться независимыми. Хороший пример — использование нескольких глобальных переменных (например,testв примере ниже). - Убедитесь, что либо вы отключили вынос выражений let за пределы области видимости (
-fno-full-laziness), либо вызовunsafePerformIOне может быть вынесен за пределы лямбда-выражения. Например, если написать:f x = unsafePerformIO (newIORef []), может оказаться, что все вызовыfиспользуют одну общую ячейку ссылочного типа. Лучше написатьf x = unsafePerformIO (newIORef [x]), поскольку в этом случае выражение не может быть вынесено за пределы лямбда-выражения.
Менее известно, что unsafePerformIO не является типобезопасной. Например:
test :: IORef [a]
test = unsafePerformIO $ newIORef []
main = do
writeIORef test [42]
bang <- readIORef test
print (bang :: [Char])
Эта программа завершится с дампом ядра. Проблема полиморфных ссылок хорошо известна в сообществе ML и не возникает при обычном использовании ссылок в монадах. После использования unsafePerformIO простого способа полностью исключить эту проблему нет. Более того, с помощью unsafePerformIO можно написать coerce :: a -> b. Будьте осторожны!
ВНИМАНИЕ: если вы ищете «способ получить String из 'IO String'», то unsafePerformIO — не то, что вам нужно. Прежде чем продолжить, изучите do-нотацию и синтаксический элемент <-.
unsafeDupablePerformIO :: IO a -> a Источник
Эта версия unsafePerformIO работает эффективнее, поскольку в ней отсутствует проверка, выполняется ли операция ввода-вывода только одним потоком. Поэтому при использовании unsafeDupablePerformIO существует вероятность, что операция ввода-вывода выполнится несколько раз (на многопроцессорной системе), и следует убедиться, что каждый раз она даёт одинаковые результаты. Может случиться даже так, что один из дублированных вызовов операции ввода-вывода выполнится лишь частично, а затем будет прерван посередине без возбуждения исключения. Поэтому такие функции, как bracket, нельзя безопасно использовать внутри unsafeDupablePerformIO.
Начиная с: base-4.4.0.0
unsafeInterleaveIO :: IO a -> IO a Источник
unsafeInterleaveIO позволяет отложить вычисление IO с использованием ленивой семантики. Если передать значение типа IO a, вычисление IO будет выполнено только тогда, когда потребуется значение a. Эта возможность используется для реализации ленивого чтения файлов; см. hGetContents.
unsafeFixIO :: (a -> IO a) -> IO a Источник
Немного более быстрая версия fixIO, которая может быть небезопасна при использовании в нескольких потоках. Небезопасность проявляется в следующем случае:
unsafeFixIO $ \r -> do
forkIO (print r)
return (...)
В этом случае дочерний поток получит исключение NonTermination вместо ожидания вычисления значения r.
Начиная с: base-4.5.0.0
© The University of Glasgow and others
Licensed under a BSD-style license (see top of the page).
https://downloads.haskell.org/~ghc/9.14.1/docs/libraries/base-4.22.0.0-66f8/System-IO-Unsafe.html