Spec-Zone.ru › Haskell 9

GHC.IO

Авторские права (c) The University of Glasgow 1994-2023
Лицензия см. libraries/base/LICENSE
Сопровождающие ghc-devs@haskell.org
Стабильность внутренний
Переносимость непереносимый (расширения GHC)
Безопасный Haskell отсутствует
Язык Haskell2010

Описание

Определения для монады IO и связанных с ней сущностей.

API этого модуля нестабилен и не предназначен для использования широкой публикой. Если вам совершенно необходимо от него зависеть, обязательно задайте строгую верхнюю границу версии, например base < 4.X вместо base < 5, поскольку интерфейс может быстро измениться без особого предупреждения.

newtype IO a Source

Значение типа IO a — это вычисление, которое при выполнении производит некоторые операции ввода-вывода, а затем возвращает значение типа a.

На самом деле существует лишь один способ «выполнить» действие ввода-вывода: связать его с Main.main в вашей программе. При запуске программы ввод-вывод будет выполнен. Невозможно выполнять ввод-вывод из произвольной функции, если только сама эта функция не находится в монаде IO и не вызывается в какой-то момент, прямо или косвенно, из Main.main.

IO — это монада, поэтому действия IO можно объединять, используя do-нотацию или операции >> и >>= из класса Monad.

Конструкторы

IO (State# RealWorld -> (# State# RealWorld, a #))
Экземпляры
Подробности экземпляров
Alternative IO Исходный код

Возвращает результат первого действия IO, не приводящего к выбросу исключения. empty выбрасывает исключение.

Начиная с: base-4.9.0.0

Подробности экземпляра

Определено в GHC.Internal.Base

Методы

empty :: IO a Исходный код

(<|>) :: IO a -> IO a -> IO a Исходный код

some :: IO a -> IO [a] Исходный код

many :: IO a -> IO [a] Исходный код

Applicative IO Исходный код

Начиная с: base-2.1

Подробности экземпляра

Определено в GHC.Internal.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 Исходный код

Functor IO Исходный код

Начиная с: base-2.1

Подробности экземпляра

Определено в GHC.Internal.Base

Методы

fmap :: (a -> b) -> IO a -> IO b Исходный код

(<$) :: a -> IO b -> IO a Исходный код

Monad IO Исходный код

Начиная с: base-2.1

Подробности экземпляра

Определено в GHC.Internal.Base

Методы

(>>=) :: IO a -> (a -> IO b) -> IO b Исходный код

(>>) :: IO a -> IO b -> IO b Исходный код

return :: a -> IO a Исходный код

MonadPlus IO Исходный код

Возвращает результат первого действия IO, не приводящего к выбросу исключения. mzero выбрасывает исключение.

Начиная с: base-4.9.0.0

Подробности экземпляра

Определено в GHC.Internal.Base

Методы

mzero :: IO a Исходный код

mplus :: IO a -> IO a -> IO a Исходный код

MonadFail IO Исходный код

Начиная с: base-4.9.0.0

Подробности экземпляра

Определено в GHC.Internal.Control.Monad.Fail

Методы

fail :: HasCallStack => String -> IO a Исходный код

MonadFix IO Исходный код

Начиная с: base-2.1

Подробности экземпляра

Определено в GHC.Internal.Control.Monad.Fix

Методы

mfix :: (a -> IO a) -> IO a Исходный код

MonadIO IO Исходный код

Начиная с: base-4.9.0.0

Подробности экземпляра

Определено в GHC.Internal.Control.Monad.IO.Class

Методы

liftIO :: IO a -> IO a Исходный код

GHCiSandboxIO IO Исходный код

Начиная с: base-4.4.0.0

Подробности экземпляра

Определено в GHC.Internal.GHCi

Методы

ghciStepIO :: IO a -> IO a Исходный код

Quasi IO Исходный код
Подробности экземпляра

Определено в GHC.Internal.TH.Syntax

Методы

qNewName :: String -> IO Name Исходный код

qReport :: Bool -> String -> IO () Исходный код

qRecover :: IO a -> IO a -> IO a Исходный код

qLookupName :: Bool -> String -> IO (Maybe Name) Исходный код

qReify :: Name -> IO Info Исходный код

qReifyFixity :: Name -> IO (Maybe Fixity) Исходный код

qReifyType :: Name -> IO Type Исходный код

qReifyInstances :: Name -> [Type] -> IO [Dec] Исходный код

qReifyRoles :: Name -> IO [Role] Исходный код

qReifyAnnotations :: Data a => AnnLookup -> IO [a] Исходный код

qReifyModule :: Module -> IO ModuleInfo Исходный код

qReifyConStrictness :: Name -> IO [DecidedStrictness] Исходный код

qLocation :: IO Loc Исходный код

qRunIO :: IO a -> IO a Исходный код

qGetPackageRoot :: IO FilePath Исходный код

qAddDependentFile :: FilePath -> IO () Исходный код

qAddTempFile :: String -> IO FilePath Исходный код

qAddTopDecls :: [Dec] -> IO () Исходный код

qAddForeignFilePath :: ForeignSrcLang -> String -> IO () Исходный код

qAddModFinalizer :: Q () -> IO () Исходный код

qAddCorePlugin :: String -> IO () Исходный код

qGetQ :: Typeable a => IO (Maybe a) Исходный код

qPutQ :: Typeable a => a -> IO () Исходный код

qIsExtEnabled :: Extension -> IO Bool Исходный код

qExtsEnabled :: IO [Extension] Исходный код

qPutDoc :: DocLoc -> String -> IO () Исходный код

qGetDoc :: DocLoc -> IO (Maybe String) Исходный код

Quote IO Исходный код
Подробности экземпляра

Определено в GHC.Internal.TH.Syntax

Методы

newName :: String -> IO Name Исходный код

a ~ () => HPrintfType (IO a) Исходный код

Начиная с: base-4.7.0.0

Подробности экземпляра

Определено в Text.Printf

Методы

hspr :: Handle -> String -> [UPrintf] -> IO a

a ~ () => PrintfType (IO a) Исходный код

Начиная с: base-4.7.0.0

Подробности экземпляра

Определено в Text.Printf

Методы

spr :: String -> [UPrintf] -> IO a

Monoid a => Monoid (IO a) Исходный код

Начиная с: base-4.9.0.0

Сведения об экземпляре

Определено в GHC.Internal.Base

Методы

mempty :: IO a Источник

mappend :: IO a -> IO a -> IO a Источник

mconcat :: [IO a] -> IO a Источник

Semigroup a => Semigroup (IO a) Источник

Начиная с: base-4.10.0.0

Сведения об экземпляре

Определено в GHC.Internal.Base

Методы

(<>) :: IO a -> IO a -> IO a Источник

sconcat :: NonEmpty (IO a) -> IO a Источник

stimes :: Integral b => b -> IO a -> IO a Источник

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 нет простого способа сделать такую ситуацию невозможной. Более того, с помощью unsafePerformIO можно написать coerce :: a -> b. Будьте осторожны!

ПРЕДУПРЕЖДЕНИЕ: если вы ищете «способ получить String из 'IO String'», то unsafePerformIO — не то, что вам нужно. Прежде чем продолжить, изучите do-нотацию и синтаксическую конструкцию <-.

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 Источник

Преобразует действие IO в действие ST. Тип результата ограничен использованием потока состояний RealWorld, поэтому результат нельзя передать в runST.

unsafeIOToST :: IO a -> ST s a Источник

Преобразует действие IO в действие ST. Это основано на том, что IO и ST имеют одинаковое представление, если не учитывать ограничение на параметр типа потока состояний.

unsafeSTToIO :: ST s a -> IO a Источник

Преобразует действие ST в действие IO. Это основано на том, что IO и ST имеют одинаковое представление, если не учитывать ограничение на параметр типа потока состояний.

Пример, демонстрирующий, почему это небезопасно: https://mail.haskell.org/pipermail/haskell-cafe/2009-April/060719.html

type FilePath = String Источник

Имена файлов и каталогов — это значения типа String, точное значение которого зависит от операционной системы. Файлы можно открывать, получая дескриптор, который затем используется для работы с содержимым файла.

catch Источник

Аргументы

:: 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 Источник

Перехватывает исключение в монаде IO.

Обратите внимание: эта функция является строгой относительно действия. То есть catchException undefined b == _|_. Подробности см. в .

catchAny :: IO a -> (forall e. (HasExceptionContext, Exception e) => e -> IO a) -> IO a Источник

Перехватывает исключение любого типа Exception в монаде IO.

Обратите внимание: эта функция является строгой относительно действия. То есть catchAny undefined b == _|_. Подробности см. в .

Если вы повторно выбрасываете исключение, следует повторно использовать переданный ExceptionContext.

throwIO :: (HasCallStack, Exception e) => e -> IO a Источник

Вариант throw, который можно использовать только внутри монады IO.

Хотя throwIO имеет тип, являющийся экземпляром типа throw, эти две функции немного различаются:

throw e   `seq` ()  ===> throw e
throwIO e `seq` ()  ===> ()

В первом примере будет вызвано исключение e, а во втором — нет. Фактически, throwIO вызывает исключение только при использовании внутри монады IO.

Для вызова исключения внутри монады IO следует предпочесть вариант throwIO вместо throw, поскольку он гарантирует порядок выполнения относительно других операций, а throw такой гарантии не даёт. Говорят, что throwIO выбрасывает *точные* исключения, а throw, error и т. д. выбрасывают *неточные* исключения. Например:

throw e + error "boom" ===> error "boom"
throw e + error "boom" ===> throw e

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

throwIO e >> error "boom" ===> throwIO e

при выполнении всегда вызовет e.

Более подробное техническое введение в то, как GHC оптимизирует код с учётом точных и неточных исключений, см. также на вики-странице GHC о точных исключениях.

mask :: ((forall a. IO a -> IO a) -> IO b) -> IO b Источник

Выполняет вычисление ввода-вывода с замаскированными асинхронными исключениями. Это означает, что любой поток, пытающийся вызвать исключение в текущем потоке с помощью 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_ :: IO a -> IO a Источник

Аналог mask, но аргументу не передаётся действие restore.

uninterruptibleMask :: ((forall a. IO a -> IO a) -> IO b) -> IO b Источник

Аналог mask, но замаскированное вычисление нельзя прервать (см. Control.Exception). ЭТУ ФУНКЦИЮ СЛЕДУЕТ ИСПОЛЬЗОВАТЬ С БОЛЬШОЙ ОСТОРОЖНОСТЬЮ: если поток, выполняющийся в uninterruptibleMask, по какой-либо причине заблокируется, он (а возможно, и программа, если это главный поток) перестанет отвечать и его нельзя будет завершить. Эта функция нужна только в том случае, если необходимо маскировать исключения во время прерываемой операции и можно гарантировать, что такая операция будет блокироваться лишь непродолжительное время.

uninterruptibleMask_ :: IO a -> IO a Источник

Аналог uninterruptibleMask, но аргументу не передаётся действие restore.

data MaskingState Источник

Описывает поведение потока при получении асинхронного исключения.

Конструкторы

Unmasked

асинхронные исключения не замаскированы (обычное состояние)

MaskedInterruptible

состояние во время mask: асинхронные исключения замаскированы, но блокирующие операции всё ещё могут быть прерваны

MaskedUninterruptible

состояние во время uninterruptibleMask: асинхронные исключения замаскированы, а блокирующие операции нельзя прервать

Экземпляры
Сведения об экземплярах
Eq MaskingState Источник

Начиная с: base-4.3.0.0

Сведения об экземпляре

Определено в GHC.Internal.IO

Методы

(==) :: MaskingState -> MaskingState -> Bool Источник

(/=) :: MaskingState -> MaskingState -> Bool Источник

Show MaskingState Источник

Начиная с: base-4.3.0.0

Сведения об экземпляре

Определено в GHC.Internal.IO

Методы

showsPrec :: Int -> MaskingState -> ShowS Источник

show :: MaskingState -> String Источник

showList :: [MaskingState] -> ShowS Источник

getMaskingState :: IO MaskingState Источник

Возвращает MaskingState текущего потока.

unsafeUnmask :: IO a -> IO a Источник

interruptible :: IO a -> IO a Источник

Разрешает возникновение асинхронных исключений даже внутри mask, делая операцию прерываемой (см. обсуждение «Прерываемых операций» в Exception).

При вызове вне mask или внутри uninterruptibleMask эта функция не оказывает эффекта.

Начиная с: base-4.9.0.0

onException :: IO a -> IO b -> IO a Источник

bracket Источник

Аргументы

:: IO a

вычисление, которое нужно выполнить первым («получение ресурса»)

-> (a -> IO b)

вычисление, которое нужно выполнить последним («освобождение ресурса»)

-> (a -> IO c)

вычисление, которое нужно выполнить между ними

-> IO c

finally Источник

Аргументы

:: IO a

вычисление, которое нужно выполнить первым

-> IO b

вычисление, которое нужно выполнить после (даже если было вызвано исключение)

-> IO a

evaluate :: a -> IO a Источник

Вычисляет аргумент до слабой головной нормальной формы.

evaluate обычно используется для выявления исключений, которые может содержать ленивое значение, и, возможно, их обработки.

evaluate вычисляет значение только до слабой головной нормальной формы. Если требуется более глубокое вычисление, может пригодиться функция force из Control.DeepSeq:

evaluate $ force x

Между evaluate x и return $! 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 Источник

© 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/GHC-IO.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API