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

Более безопасные ручки в Haskell?

При использовании Haskell Handles я чувствовал себя немного небезопасно. А именно, я ищу две функции (возможно, они уже есть, и в этом случае, пожалуйста, простите мое невежество).

  • Когда я получил дескриптор (например, возвращен Network.accept), который читается и записывается, я хочу преобразовать их в пару только для чтения и только для записи, так что запись в режим только для чтения дескриптор не будет вводить проверку и наоборот. (Возможно, можно достичь это использование типов phantom и обертывания вокруг функций ввода-вывода?)
  • В параллельной настройке я обнаружил, что для нескольких потоков можно писать один и тот же дескриптор, что приводит к довольно неприятным последствиям. Как можно предотвратить это через систему типов (если возможно) или, по крайней мере, получить уведомление о таком случае через исключение броска во время выполнения?

Любая идея приветствуется.

4b9b3361

Ответ 1

Возможно, вам захочется использовать пакет сетевой кабель. Он описывает сетевое приложение как то, что дается двум "конечным точкам" - один приемник передает данные в сокет и один источник, который считывает данные из сокета:

type Application m = AppData m -> m ()

data AppData m Source -- ...
appSource :: AppData m -> Source m ByteStringSource
appSink :: AppData m -> Sink ByteString m ()

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

Если вы хотите обеспечить однопоточную обработку, вы можете ограничить себя реализацией своих программных компонентов как Conduit ByteString m ByteString. Такой трубопровод можно с радостью превратить в Application как

asApp :: MonadIO m => Conduit ByteString m ByteString -> Application m
asApp cond ad = appSource ad $= cond $$ appSink ad

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

Ответ 2

Похоже, что библиотека safer-file-handles делает то, что вы хотите. Первая часть обрабатывается довольно четко. Кажется, что concurrency -safety обрабатывается RegionT из библиотеки regions. Я не использовал это вообще, но он выглядит довольно распространенным.