GHC.IO
| Авторские права | (c) Университет Глазго 1994-2002 |
|---|---|
| Лицензия | см. libraries/base/LICENSE |
| Поддержка | cvs-ghc@haskell.org |
| Устойчивость | внутренняя |
| Переносимость | непереносимая (расширения GHC) |
| Безопасный Haskell | Небезопасный |
| Язык | Haskell2010 |
Описание
Определения для монады IO и её друзей.
Значение типа IO a — это вычисление, которое при выполнении выполняет некоторое ввод/вывод, прежде чем вернуть значение типа a.
Существует действительно только один способ "выполнить" действие ввода/вывода: связать его с Main.main в вашей программе. Когда ваша программа выполняется, ввод/вывод будет выполнен. Выполнить ввод/вывод из произвольной функции невозможно, если только эта функция сама не находится в монаде IO и вызывается в какой-то момент, прямо или косвенно, из Main.main.
IO — это монада, поэтому действия IO можно комбинировать, используя либо обозначение do, либо операции >> и >>= из класса Monad.
Экземпляры
| Monad IO | С версии: base-2.1 |
Определено в GHC.Base Методы(>>=) :: IO a -> (a -> IO b) -> IO b Исходный код (>>) :: IO a -> IO b -> IO b Исходный код return :: a -> IO a Исходный код | |
| Functor IO | С версии: base-2.1 |
Определено в GHC.Base | |
| MonadFix IO | С версии: base-2.1 |
Определено в Control.Monad.Fix Методыmfix :: (a -> IO a) -> IO a Исходный код | |
| MonadFail IO | С версии: base-4.9.0.0 |
Определено в Control.Monad.Fail Методыfail :: String -> IO a Исходный код | |
| Applicative IO | С версии: base-2.1 |
Определено в GHC.Base Методыpure :: a -> IO a Исходный код (<*>) :: IO (a -> b) -> IO a -> IO b Исходный код liftA2 :: (a -> b -> c) -> IO a -> IO b -> IO c Исходный код (*>) :: IO a -> IO b -> IO b Исходный код (<*) :: IO a -> IO b -> IO a Исходный код | |
| GHCiSandboxIO IO | С версии: base-4.4.0.0 |
Определено в GHC.GHCi МетодыghciStepIO :: IO a -> IO a Исходный код | |
| MonadPlus IO | С версии: base-4.9.0.0 |
Определено в GHC.Base | |
| Alternative IO | С версии: base-4.9.0.0 |
Определено в GHC.Base Методыempty :: IO a Исходный код (<|>) :: IO a -> IO a -> IO a Исходный код some :: IO a -> IO [a] Исходный код many :: IO a -> IO [a] Исходный код | |
| MonadIO IO | С версии: base-4.9.0.0 |
Определено в Control.Monad.IO.Class МетодыliftIO :: IO a -> IO a Исходный код | |
| Semigroup a => Semigroup (IO a) | С версии: base-4.10.0.0 |
| Monoid a => Monoid (IO a) | С момента: base-4.9.0.0 |
Определено в GHC.Base Методыmempty :: IO a Исходный код mappend :: IO a -> IO a -> IO a Исходный код mconcat :: [IO a] -> IO a Исходный код | |
| a ~ () => HPrintfType (IO a) | С момента: base-4.7.0.0 |
Определено в Text.Printf | |
| a ~ () => PrintfType (IO a) | С момента: base-4.7.0.0 |
Определено в Text.Printf | |
unIO :: IO a -> State# RealWorld -> (# State# RealWorld, a #) Исходный код
liftIO :: IO a -> State# RealWorld -> STret RealWorld a Исходный код
mplusIO :: IO a -> IO a -> IO a Исходный код
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. Действительно, можно написать coerce :: a -> b с помощью unsafePerformIO. Поэтому будьте осторожны!
unsafeInterleaveIO :: IO a -> IO a Исходный код
unsafeInterleaveIO позволяет отложить IO вычисление лениво. При передаче значения типа IO a, IO будет выполнено только при запросе значения a. Это используется для реализации ленивого чтения файлов, см. hGetContents.
unsafeDupablePerformIO :: IO a -> a Исходный код
Эта версия unsafePerformIO более эффективна, потому что она опускает проверку, что ввод-вывод выполняется только одним потоком. Следовательно, при использовании unsafeDupablePerformIO, существует вероятность того, что действие ввода-вывода может быть выполнено несколько раз (на многопроцессорной системе), и поэтому вы должны убедиться, что оно даёт одинаковые результаты каждый раз. Может даже произойти так, что одно из дублированных действий ввода-вывода будет выполнено частично, а затем прервано в середине без возникновения исключения. Поэтому функции, такие как bracket, нельзя безопасно использовать в unsafeDupablePerformIO.
С момента: base-4.4.0.0
unsafeDupableInterleaveIO :: IO a -> IO a Исходный код
unsafeDupableInterleaveIO позволяет лениво откладывать IO вычисление. При передаче значения типа IO a, IO будет выполнено только при запросе значения a.
Вычисление может быть выполнено несколько раз разными потоками, возможно, одновременно. Чтобы убедиться, что вычисление выполняется только один раз, используйте unsafeInterleaveIO вместо этого.
noDuplicate :: IO () Исходный код
Обеспечивает, что приостановки, оцениваемые текущим потоком, уникальны; то есть текущий поток не оценивает ничего, что также оценивается другим потоком, который также выполнил noDuplicate.
Эта операция используется в определении unsafePerformIO для предотвращения выполнения действия ввода-вывода несколько раз, что обычно нежелательно.
stToIO :: ST RealWorld a -> IO a Исходный код
Встроить строгий поток состояния в действие IO. Параметр RealWorld указывает, что внутреннее состояние, используемое вычислением ST, является специальным, предоставляемым монадой IO, и отличается от состояний, используемых вызовами runST.
ioToST :: IO a -> ST RealWorld a Source
Преобразовать действие IO в действие ST. Тип результата ограничен использованием потока состояния RealWorld, и поэтому результат нельзя передать в runST.
unsafeIOToST :: IO a -> ST s a Source
Преобразование действия IO в действие ST. Это основано на том, что IO и ST имеют одинаковое представление с учётом ограничения на тип параметра потока состояния.
unsafeSTToIO :: ST s a -> IO a Source
Преобразование действия ST в действие IO. Это основано на том, что IO и ST имеют одинаковое представление с учётом ограничения на тип параметра потока состояния.
Пример, демонстрирующий, почему это небезопасно, см. https://mail.haskell.org/pipermail/haskell-cafe/2009-April/060719.html
Имена файлов и каталогов — значения типа String, точное значение которых зависит от операционной системы. Файлы могут быть открыты, что приводит к получению дескриптора, который затем может быть использован для работы с содержимым файла.
Аргументы
| :: Exception e | |
| => IO a | Вычисление для выполнения |
| -> (e -> IO a) | Обработчик для вызова, если возникает исключение |
| -> IO a |
Это простейшая функция обработки исключений. Она принимает один аргумент, выполняет его, и если возникает исключение, выполняется "обработчик" с значением исключения в качестве аргумента. В противном случае результат возвращается обычно. Например:
catch (readFile f)
(\e -> do let err = show (e :: IOException)
hPutStr stderr ("Warning: Couldn't open " ++ f ++ ": " ++ err)
return "")
Обратите внимание, что нам нужно указать сигнатуру типа для e, иначе программа не пройдёт типизацию, так как тип неоднозначен. Хотя можно перехватывать исключения любого типа, см. раздел "Перехват всех исключений" (в Control.Exception) для объяснения проблем с этим.
Для перехвата исключений в чистых (не IO) выражениях см. функцию evaluate.
Обратите внимание, что из-за неопределённого порядка вычислений Haskell выражение может выбросить одно из нескольких возможных исключений: рассмотрим выражение (error "urk") + (1 `div` 0). Выбрасывает ли выражение ErrorCall "urk" или DivideByZero?
Ответ: "может выбросить любое из них"; выбор не детерминирован. Если вы перехватываете любой тип исключения, то можете перехватить любое из них. Если вы вызываете catch с типом IO Int -> (ArithException -> IO Int) -> IO Int, то обработчик может быть вызван с DivideByZero в качестве аргумента, или исключение ErrorCall "urk" может быть передано выше. Если вы вызовете это снова, вы можете получить обратное поведение. Это нормально, потому что catch — это вычисление в монаде IO.
catchException :: Exception e => IO a -> (e -> IO a) -> IO a Source
Перехват исключения в монаде IO.
Обратите внимание, что эта функция является строгой по отношению к действию. То есть, catchException undefined b == _|_. См. для подробностей.
catchAny :: IO a -> (forall e. Exception e => e -> IO a) -> IO a Source
Перехват исключений любого типа в монаде IO.
Обратите внимание, что эта функция является строгой по отношению к действию. То есть, catchAny undefined b == _|_. См. для подробностей.
throwIO :: Exception e => e -> IO a Source
Вариант throw который может быть использован только внутри монады IO.
Несмотря на то, что throwIO имеет тип, являющийся экземпляром типа throw две функции отличаются в деталях:
throw e `seq` x ===> throw e throwIO e `seq` x ===> x
Первый пример вызовет исключение e, в то время как второй — нет. Фактически, throwIO вызовет исключение только когда используется внутри монады IO.
Вариант throwIO следует использовать по предпочтению throw для повышения исключения внутри монады IO, так как он гарантирует порядок относительно других операций IO, тогда как throw этого не делает.
mask :: ((forall a. IO a -> IO a) -> IO b) -> IO b Source
Выполняет вычисление IO с замаскированными асинхронными исключениями. То есть, любая нить, которая пытается вызвать исключение в текущей нити с throwTo будет заблокирована до тех пор, пока асинхронные исключения не будут снова размаскированы.
Переданный в mask аргумент — функция, принимающая в качестве аргумента другую функцию, которая может быть использована для восстановления текущего состояния маскировки в контексте вычисления с маской. Например, распространённый способ использования mask — это защита получения ресурса:
mask $ \restore -> do
x <- acquire
restore (do_something_with x) `onException` release
release
Этот код гарантирует, что acquire парно с release, маскируя асинхронные исключения для критических участков. (Вместо написания этого кода лучше использовать bracket, которая абстрагирует общий шаблон).
Обратите внимание, что действие restore , переданное в качестве аргумента mask , не обязательно размаскирует асинхронные исключения, оно только восстанавливает состояние маскировки до состояния внешнего контекста. Таким образом, если асинхронные исключения уже замаскированы, mask не может быть использована для размаскирования исключений. Это позволяет, если вы вызываете функцию библиотеки с замаскированными исключениями, быть уверенным, что вызов библиотеки не сможет снова размаскировать исключения. Если вы пишете код библиотеки и вам нужно использовать асинхронные исключения, единственный способ — создать новую нить; см. forkIOWithUnmask.
Асинхронные исключения всё ещё могут быть получены во время маскирования, если замаскированная нить блокируется определённым образом; см. Control.Exception.
Потоки, созданные forkIO наследуют состояние MaskingState от родителя; то есть, чтобы запустить поток в состоянии MaskedInterruptible, используйте mask_ $ forkIO .... Это особенно полезно, если вам нужно установить обработчик исключений в разветвлённом потоке перед получением любых асинхронных исключений. Чтобы создать новый поток в размаскированном состоянии, используйте forkIOWithUnmask.
Как mask, но не передаёт действие restore в аргумент.
uninterruptibleMask :: ((forall a. IO a -> IO a) -> IO b) -> IO b Source
Как и mask, но замаскированное вычисление не прерывается (см. Control.Exception). ЭТО НУЖНО ИСПОЛЬЗОВАТЬ С ОСТОРОЖНОСТЬЮ, потому что если поток, выполняющийся в uninterruptibleMask, блокируется по какой-либо причине, то поток (а возможно и программа, если это главный поток) станет неотзываемым и неуничтожимым. Эта функция должна потребоваться только в том случае, если вам нужно замаскировать исключения вокруг прерывимой операции, и вы можете гарантировать, что прерывимая операция будет заблокирована только на короткое время.
uninterruptibleMask_ :: IO a -> IO a Source
Как и uninterruptibleMask, но не передает restore действие аргументу.
data MaskingState Source
Описывает поведение потока при получении асинхронного исключения.
Конструкторы
| Unmasked | асинхронные исключения не маскируются (обычное состояние) |
| MaskedInterruptible | состояние во время |
| MaskedUninterruptible | состояние во время |
Примеры
| Eq MaskingState | С версии: base-4.3.0.0 |
Определено в GHC.IO Методы(==) :: MaskingState -> MaskingState -> Bool Source (/=) :: MaskingState -> MaskingState -> Bool Source | |
| Show MaskingState | С версии: base-4.3.0.0 |
Определено в GHC.IO МетодыshowsPrec :: Int -> MaskingState -> ShowS Source show :: MaskingState -> String Source showList :: [MaskingState] -> ShowS Source | |
getMaskingState :: IO MaskingState Source
Возвращает MaskingState для текущего потока.
unsafeUnmask :: IO a -> IO a Source
interruptible :: IO a -> IO a Source
Разрешает асинхронные исключения, даже внутри mask, делая операцию прерывимой (см. обсуждение «Прерывимые операции» в Exception).
При вызове вне mask или внутри uninterruptibleMask, эта функция не оказывает никакого эффекта.
С версии: base-4.9.0.0
onException :: IO a -> IO b -> IO a Source
Аргументы
| :: IO a | вычисление, которое выполняется в первую очередь («получить ресурс») |
| -> (a -> IO b) | вычисление, которое выполняется последним («освободить ресурс») |
| -> (a -> IO c) | вычисление, которое выполняется между ними |
| -> IO c |
Аргументы
| :: IO a | вычисление, которое выполняется в первую очередь |
| -> IO b | вычисление, которое выполняется после (даже если было вызвано исключение) |
| -> IO a |
Вычисляет аргумент до слабой головной нормальной формы.
evaluate обычно используется для обнаружения любых исключений, которые может содержать ленивое значение, и, возможно, их обработки.
evaluate вычисляется только до слабой головной нормальной формы. Если требуется более глубокое вычисление, функция force из Control.DeepSeq может быть полезной:
evaluate $ force x
Существует тонкое различие между evaluate x и x, аналогичное различию между throwIO и throw. Если ленивое значение x вызывает исключение, return $! x не вернёт IO действие и вместо этого вызовет исключение. evaluate x, с другой стороны, всегда производит IO действие; это действие вызовет исключение при выполнении тогда и только тогда, когда x вызывает исключение при вычислении.
Практическое следствие этого различия заключается в том, что из-за семантики неточных исключений,
(return $! error "foo") >> error "bar"
может вызвать либо "foo", либо "bar", в зависимости от оптимизаций, выполняемых компилятором. С другой стороны,
evaluate (error "foo") >> error "bar"
гарантировано вызовет "foo".
Правило гласит: используйте evaluate для принуждения или обработки исключений в ленивых значениях. Если же вы принуждаете ленивое значение только по соображениям эффективности и не беспокоитесь об исключениях, можно использовать return $! x.
mkUserError :: [Char] -> SomeException Source
© The University of Glasgow and others
Licensed under a BSD-style license (see top of the page).
https://downloads.haskell.org/~ghc/8.10.2/docs/html/libraries/base-4.14.1.0/GHC-IO.html