簡體   English   中英

Haskell 序列的 IO 動作處理並實時過濾它們的結果+在某些時刻執行一些 IO 動作

[英]Haskell sequence of IO actions processing with filtration their results in realtime+perfoming some IO actions in certain moments

I want to do some infinite sequence of IO actions processing with filtration their results in realtime+perfoming some IO actions in certain moments: We have some function for reducing sequences (see my question haskell elegant way to filter (reduce) sequences of duplicates from infinte數字列表):

f :: Eq a => [a] -> [a]
f = map head . group

和表達

join $ sequence <$> ((\l -> (print <$> l)) <$> (f <$> (sequence $ replicate 6 getLine)))

如果我們運行它,用戶可以生成任何數字序列,例如:

1
2
2
3
3
"1"
"2"
"3"
[(),(),()]

這意味着首先執行所有 getLine 操作(在示例中為 6 次,最后執行所有 IO 操作以執行過濾列表,但我想恰好在時刻執行 IO 操作,然后排序減少對相同數字的某些子序列完成.

如何存檔此 output:

1     
2
"1"
2     
3
"2"        
3
3
"3"
[(),(),()]

所以我希望這個表達式不掛起:

 join $ sequence <$> ((\l -> (print <$> l)) <$> (f <$> (sequence $ repeat getLine)))

如何按上述方式歸檔實時 output 而不會在無限列表中阻止它?

這似乎是流媒體庫的工作,例如流媒體

{-# LANGUAGE ImportQualifiedPost #-}
module Main where

import Streaming
import Streaming.Prelude qualified as S

main :: IO ()
main =
      S.mapM_ print
    . S.catMaybes
    . S.mapped S.head
    . S.group
    $ S.replicateM 6 getLine

“流”有一個 API 讓人想起列表,但適用於有效的序列。

流式group版本的好處在於,如果不需要,它不會強迫您將整個組保留在 memory 中。


此答案中最不直觀的 function 是mapped ,因為它非常通用。 流式傳輸的head版本是否適合作為其參數並不明顯。 關鍵思想是Stream類型可以表示正常有效序列,也可以表示已划分組的元素序列。 這是通過更改仿函數類型參數來控制的( Of在第一種情況下,嵌套Stream (Of a) m分組Stream s的情況下)。

mapped讓您在對底層 monad 產生一些影響的同時轉換該函子參數(此處IO )。 head處理內部Stream (Of a) m組,讓我們回到Of (Maybe a)函子參數。

如果沒有第三方庫,您可以懶惰地讀取標准輸入的內容,在預期輸入的末尾附加一個虛擬字符串以強制 output。 (可能有一個更好的解決方案,我愚蠢地忽略了。)

import System.IO

print_unique :: (String, String) -> IO ()
print_unique (last, current) | last == current = return ()
                             | otherwise = print last

main = do
  contents <- take 6 <$> lines <$> hGetContents stdin
  traverse print_unique (zip <*> tail $ (contents ++ [""]))

zip <*> tail生成由第i行和第i+1行組成的元組,而不會阻塞。 如果以下行不同,則print_unique然后立即輸出一行。

本質上,您是在執行輸入時對 output 操作進行排序,而不是對輸入操作進行排序。

我用 iterateUntilM 找到了一個很好的解決方案

iterateUntilM (\_->False) (\pn -> getLine >>= (\n -> if n==pn then return n else (if pn/="" then print pn else return ()) >> return n) ) ""

我不喜歡冗長的

(if pn/="" then print pn else return ())

如果您知道如何減少這種情況,請發表評論)

附言。 值得注意的是,我制作了一個關於這個 function 的視頻:) 並不能立即應用它:(

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM