Потоковая передача ресурса с правильным приобретением и выпуском - PullRequest
0 голосов
/ 07 июня 2018

Это вопрос о библиотеке Haskell streaming.

Stream (Of a) m r - это «поток отдельных значений Haskell, полученных из действий в некоторой монаде m и возвращающих значение типа r».Streaming.Prelude определяет множество полезных функций, которые позволяют создавать хорошие потоковые приложения:

import qualified Streaming.Prelude as S
S.print $ do
    S.yield "a"
    S.yield "b"
    S.yield "c"

Учебное пособие хорошо для начала.

Теперь конкретная проблема под рукойкак использовать этот фреймворк с монадой, требующей тщательной реализации и освобождения ресурсов.Пакет streaming-with кажется подходящим кандидатом, он имеет функцию

bracket :: MonadMask m => m a -> (a -> m c) -> (a -> m b) -> m b

, которая получает (m a), освобождает (a->m c) и использует (* 1025)*) ресурс.Все три действия заключены в возвращенном m b.withFile является хорошим примером того, как использовать это:

withFile :: FilePath -> IOMode -> (Handle -> m r) -> m r
withFile fp md = bracket (liftIO (openFile fp md)) (liftIO . hClose)

Получение и выпуск ручки приятно совмещают использование Handle->m r.

Но: я абсолютно не вижукак это следует использовать с Stream (Of a) m r.Я должен предоставить a->m b, и я получу m b.Как это должно быть связано, чтобы я получил Stream?

Чтобы понять это, давайте поиграем с withFile:

import System.IO 

use :: Handle -> IO (S.Stream (Of String) IO ())
use = return . S.repeatM . hGetLine

main :: IO ()
main = do
    str <- S.withFile "input.dat" ReadMode use
    S.print str

, но в результате получим hGetLine: illegal operation (handle is closed),Это действительно имеет смысл, к тому времени, когда S.print str называется withFile, уже получил и отпустил ручку.Итак, давайте переместим потребление потока внутри функции use:

use :: Handle -> IO ()
use h = do
    S.print $ S.repeatM (hGetLine h)

, и это даст hGetLine: invalid argument (invalid byte sequence).Я не совсем уверен, что означает эта ошибка.isEOFError будет приемлемым, но «недопустимая последовательность байтов»?В любом случае, это тоже не работает.

У меня заканчиваются идеи ... Как это сделать?

* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

- просто игрушечный пример, вопрос в том, как правильно создать и использовать поток внутри bracket. *1059*

1 Ответ

0 голосов
/ 07 июня 2018

давайте переместим потребление потока внутри функции использования

Это действительно правильный подход.

Я на самом деле получаю правильное hGetLine: end of file при запускепример кода.Проблема в том, что S.repeatM (hGetLine h) никогда не проверяет, достиг ли он конца файла, и выдает исключение, когда сталкивается с ним.

В следующем определении use такой проблемы нет:

use :: Handle -> IO ()
use h = do
    S.print $ S.untilRight $ do eof <- System.IO.hIsEOF h
                                if eof then Right <$> pure ()
                                       else Left <$> hGetLine h

Используется функция untilRight.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...