簡體   English   中英

Haskell處理[IO String]

[英]Haskell processing [IO String]

我有以下功能:

lines' :: [IO String]
lines' = getLine : lines'

我希望我可以在這個列表中使用所有強大的列表函數,比如過濾器等。但是我對haskell中IO monad的了解是可以改進的。

在使用Rx for C#之后,io_stuff-list列表使我信服。

有沒有辦法在哈斯克爾做我想要的? 就像是:

ten_lines :: [IO String]
ten_lines = take 10 lines'

proc_lines :: [IO String]
proc_lines = [ (l, length l) | l <- lines' ]

謝謝!

修改了一大堆常規列表函數以與Control.Monad monad一起使用。 您的問題特別感興趣:

sequence :: Monad m => [m a] -> m [a]
mapM     :: Monad m => (a -> m b) -> [a] -> m [b]
filterM  :: Monad m => (a -> m Bool) -> [a] -> m [a]
foldM    :: Monad m => (a -> b -> m a) -> a -> [b] -> m a

sequencemapM實際上是由前奏導出的,默認情況下可用。)

例如,讓我們來看看你的take 10 lines'的類型:

Prelude Control.Monad> :t take 10 lines'
take 10 lines' :: [IO String]

我們希望將此[IO String]轉換為單個IO [String]操作。 這正是sequence所做的! 我們可以通過類型簽名來告訴我們。 所以:

sequence $ take 10 lines'

會做你想做的。

這些函數中的大多數也有一個以_結尾的版本,如sequence_ 這與普通函數具有完全相同的效果,除了它拋棄結果,而是返回() 也就是說, sequence_ :: [ma] -> m () 當你實際上並不關心結果時,這是一個很好的選擇有兩個原因:它更清楚你的意圖,性能可以更好。

因此,如果你想打印 10行而不是獲取它們,你會寫這樣的東西:

printLines = putStrLn "foo" : printLines

main = sequence_ $ take 10 printLines

Tikhon的解決方案是最簡單的解決方案,但它有一個主要缺點:在處理整個列表之前它不會產生任何結果,如果處理過大的列表,它將會溢出。

更接近C#的Rx的解決方案是使用像pipes一樣的流媒體庫。

例如,您可以定義一個從用戶輸入生成StringProducer

import Control.Monad
import Control.Proxy

lines' :: (Proxy p) => () -> Producer p String IO r
lines' () = runIdentityP $ forever $ do
    str <- lift getLine
    respond str

然后你可以定義一個占用10行的舞台:

take' :: (Monad m, Proxy p) => Int -> () -> Pipe p a a m ()
take' n () = runIdentityP $ replicateM_ n $ do
    a <- request ()
    respond a

......然后是處理階段:

proc :: (Monad m, Proxy p) => () -> Pipe p String (String, Int) m r
proc () = runIdentityP $ forever $ do
    str <- request ()
    respond (str, length str)

......以及最后的輸出階段:

print' :: (Proxy p, Show a) => () -> Consumer p a IO r
print' () = runIdentityP $ forever $ do
    a <- request ()
    lift $ print a

現在,您可以將這些組成一個處理鏈並運行它:

main = runProxy $ lines' >-> take' 10 >-> proc >-> print'

...並且在輸入每一行后立即輸出處理結果,而不是在結尾處作為批次提供結果:

$ ./pipes
Apple<Enter>
("Apple",5)
Test<Enter>
("Test",4)
123<Enter>
("123",3)
4<Enter>
("4",1)
5<Enter>
("5",1)
6<Enter>
("6",1)
7<Enter>
("7",1)
8<Enter>
("8",1)
9<Enter>
("9",1)
10<Enter>
("10",2)
$

實際上,您不必自己定義這些管道。 您可以從pipes標准庫中的組件組裝相同的鏈:

>>> runProxy $ stdinS >-> takeB_ 10 >-> mapD (\x -> (x, length x)) >-> printD
<exact same behavior>

暫無
暫無

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

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