2016-03-01 2 views
0

У меня естьСэмплирование MVar, могу ли я избежать небезопасногоPerformIO?

sample :: MVar a -> IO [a] 
sample v = do 
    a <- takeMVar v 
    pure (a:unsafePerformIO (sample v)) 

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

+0

Как это более опасно, чем действие readLn. В конце концов, результат IO [a] – heisenbug

+4

Я не был бы уверен, что это законное использование Fᴜɴᴄᴛɪᴏɴ ᴛʜᴀᴛ ꜱʜᴀʟʟ ɴᴏᴛ ʙᴇ ɴᴀᴍᴇᴅ. С параллелизмом в игре есть всевозможные вещи, которые могут пойти не так, если компилятор ошибается с предположениями прозрачности прозрачности. Если 'sample' работал действительно безопасно, то это, вероятно, уже было в библиотеке. – leftaroundabout

+2

Если вы собираетесь использовать «небезопасный» маршрут, вы должны, по крайней мере, использовать здесь 'unsafeInterleaveIO', который является предполагаемым методом реализации ленивого ввода-вывода. Обратите внимание, что 'getChanContents' сам использует' unsafeInterleaveIO' для ленивого создания всего содержимого Chan. – user2407038

ответ

7

Вы можете реализовать подобную функцию, используя нить, Chan и getChanContents:

sample :: MVar a -> IO [a] 
sample v = do 
    c <- newChan 
    forkIO $ forever $ takeMVar v >>= writeChan c 
    getChanContents c 

Нить/getChanContents подход немного лучше, так как по крайней мере, вы можете рассчитывать на MVar непрерывно принимаются. Вместо этого подход unsafePerformIO будет запускаться takeMVar в непрогнозируемых точках, что делает блокировку putMVar так же непредсказуемым образом. Разумеется, подход getChanContents будет буферизовать все данные, возможно, потребует больше памяти.

Однако оба подхода по существу похожи на ленивый IO, чего лучше всего избегать, на мой взгляд.

+0

Я согласен с этим, во всех аспектах. – leftaroundabout

+0

Не могли бы вы объяснить, каким образом 'getChanContents' более предсказуем, чем использование' unsafePerformIO'. Я думаю, что с другими подходами, чем ленивый IO, вы обращаетесь к вещам вроде ['pipe'] (https://hackage.haskell.org/package/pipes) или [' conduit'] (https://hackage.haskell.org/ пакет/канал). – epsilonhalbe

+1

@epsilonhalbe Одно (по общему признанию, нетехническое) преимущество 'getChanContents' вручную с помощью' unsafePerformIO': оно поддерживается экспертами как в GHC, так и в параллелизме; он также более широко используется, чем решение доморощенного, и, следовательно, более вероятно, будет проверкой, если/когда ошибка в его реализации ползет. –

Смежные вопросы