Spec-Zone.ru › Haskell 9

System.IO.Unsafe

Авторские права (c) The University of Glasgow 2001
Лицензия в стиле BSD (см. файл libraries/base/LICENSE)
Сопровождающий libraries@haskell.org
Стабильность предварительная
Переносимость переносимая
Безопасный Haskell Небезопасный
Язык Haskell2010

Содержание

  • Небезопасные операции IO

Описание

«Небезопасные» операции ввода-вывода.

Небезопасные операции 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

Spec-Zone.ru

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