Подтвердить что ты не робот

Инициализация библиотеки unsafePerformIO и FFI

Я создаю модуль FFI для библиотеки в C, которая хочет, чтобы одна-единственная, не возвращающая функцию функция вызывалась раньше всего. Этот вызов является idempotent, но stateful, поэтому я мог бы просто позвонить ему в каждом вызове Haskell. Но он медленный и из-за не-повторного вмешательства, это может вызвать конфликты.

Итак, это подходящее время для использования unsafePerformIO? Я мог бы обернуть Bool в небезопасный IORef или MVar, чтобы эти именованные вызовы идемпотент проигнорировали последующие вызовы (вызовы, где глобальное, скрытое состояние IORef - False).

Если нет, каков правильный способ сделать это?

4b9b3361

Ответ 1

Я предпочитаю один раз инициализировать один раз и предоставить неприемлемый токен в качестве доказательства того, что вы инициализировали машину.

Итак, ваши доказательства:

data Token = Token

который вы экспортируете абстрактно.

Тогда ваша функция инициализации может вернуть это доказательство.

init :: IO Token

Теперь вам нужно передать это доказательство в свой API:

bar  :: Token -> IO Int
bar !tok = c_call_bar

и др.

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

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

Ответ 2

Я хотел бы отметить, что в настоящее время предлагается новый трюк для <вместо withSocketsDo Нила Митчелла, на основе evaluate ( "Заставляет его аргумент оцениваться к нормальной нормальной форме головы, когда выполняется результат IO." ):

withSocketsDo act = do evaluate withSocketsInit; act 

{-# NOINLINE withSocketsInit #-}
withSocketsInit = unsafePerformIO $ do
    initWinsock
    termWinsock

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

Не обязательно это прекрасная идея...

(см. также его ответ, объявив об этом обновлении в библиотеке.)