Haskell 实时过滤结果的 IO 操作序列 + 在特定时刻执行一些 IO 操作
Haskell sequence of IO actions processing with filtration their results in realtime+perfoming some IO actions in certain moments
我想做一些无限序列的 IO 操作处理,实时过滤它们的结果+在特定时刻执行一些 IO 操作:
我们有一些减少序列的功能(见我的问题):
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 操作,然后排序减少完成一些相同数字的子序列。
如何存档此输出:
1
2
"1"
2
3
"2"
3
3
"3"
[(),(),()]
所以我希望这个表达式不挂起:
join $ sequence <$> ((\l -> (print <$> l)) <$> (f <$> (sequence $ repeat getLine)))
如何按上述方式存档实时输出而不在无限列表中阻塞它?
这似乎是流媒体库的工作,例如 streaming。
{-# 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
的好处在于,如果不需要,它不会强制您将整个组保存在内存中。
这个答案中最不直观的函数是mapped
, because it's very general. It's not obvious that streaming's version of head
fits as its parameter. The key idea is that the Stream
type can represent both normal effectful sequences, and sequences of elements on which groups have been demarcated. This is controlled by changing a functor type parameter (Of
in the first case, a nested Stream (Of a) m
in the case of grouped Stream
s)。
mapped
让我们转换该仿函数参数,同时在底层 monad 中产生一些影响(此处 IO
)。 head
处理内部 Stream (Of a) m
组,让我们回到 Of (Maybe a)
仿函数参数。
没有第 3 方库,您可以延迟读取标准输入的内容,在预期输入的末尾附加一个虚拟字符串以强制输出。 (我愚蠢地忽略了可能有更好的解决方案。)
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
如果下一行不同,则立即输出一行。
本质上,您是在执行输入时对输出操作进行排序,而不是对输入操作进行排序。
我用 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 ())
如果你知道如何减少这个请评论)
ps。
值得注意的是,我对这个功能做了一个 video :)
并且无法立即应用它:(
我想做一些无限序列的 IO 操作处理,实时过滤它们的结果+在特定时刻执行一些 IO 操作:
我们有一些减少序列的功能(见我的问题
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 操作,然后排序减少完成一些相同数字的子序列。
如何存档此输出:
1
2
"1"
2
3
"2"
3
3
"3"
[(),(),()]
所以我希望这个表达式不挂起:
join $ sequence <$> ((\l -> (print <$> l)) <$> (f <$> (sequence $ repeat getLine)))
如何按上述方式存档实时输出而不在无限列表中阻塞它?
这似乎是流媒体库的工作,例如 streaming。
{-# 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
的好处在于,如果不需要,它不会强制您将整个组保存在内存中。
这个答案中最不直观的函数是mapped
, because it's very general. It's not obvious that streaming's version of head
fits as its parameter. The key idea is that the Stream
type can represent both normal effectful sequences, and sequences of elements on which groups have been demarcated. This is controlled by changing a functor type parameter (Of
in the first case, a nested Stream (Of a) m
in the case of grouped Stream
s)。
mapped
让我们转换该仿函数参数,同时在底层 monad 中产生一些影响(此处 IO
)。 head
处理内部 Stream (Of a) m
组,让我们回到 Of (Maybe a)
仿函数参数。
没有第 3 方库,您可以延迟读取标准输入的内容,在预期输入的末尾附加一个虚拟字符串以强制输出。 (我愚蠢地忽略了可能有更好的解决方案。)
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
如果下一行不同,则立即输出一行。
本质上,您是在执行输入时对输出操作进行排序,而不是对输入操作进行排序。
我用 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 ())
如果你知道如何减少这个请评论)
ps。 值得注意的是,我对这个功能做了一个 video :) 并且无法立即应用它:(