我有以下功能:
main = do xs <- getContents
edLines <- ed $ lines xs
putStr $ unlines edLines
首先,我使用了作業版本,main = interact (unlines . ed . lines)但更改了ed自簽名。現在它回傳IO [String]而不是僅僅[String]這樣我就不能再使用這個方便的定義了。
問題是,現在我的函式ed仍在部分評估,但在我通過 CTRL D 關閉標準輸入之前,什么都沒有顯示。
的定義ed:
ed :: Bool -> [EdCmdLine] -> IO EdLines
ed xs = concatM $ map toLinesExt $ scanl (flip $ edLine defHs) (return [Leaf ""]) xs where
toLinesExt :: IO [EdState] -> IO EdLines
toLinesExt rsIO = do
rs@(r:_) <- rsIO -- todo add fallback pattern with (error)
return $ fromEd r [" "]
在scanl絕對評價懶惰,因為edLine是越來越評估確認(由副作用觀察到的)。
我認為這可能與concatM:
concatM :: (Foldable t, Monad m) => t (m [a]) -> m [a]
concatM xsIO = foldr (\accIO xIO -> do {x <- xIO; acc <- accIO; return $ acc x}) (return []) xsIO
uj5u.com熱心網友回復:
Haskell 中的所有 I/O 都是明確排序的。main函式的最后兩行desugar 變成類似
ed (lines xs) >>= (\edLines -> putStr $ unlines edLines)
>>=將左側的所有 I/O 效果排序在右側的所有效果之前。您正在構建形式為 的 I/O 操作generate line 1 >> ... >> generate line n >> output line 1 >> ... >> output line n。
這實際上不是評估順序問題,而是正確性問題。一個實作可以按照它想要的任何順序自由地求值,但它不能改變你指定的 I/O 操作的順序,就像它不能重新排序串列的元素一樣。
這是一個玩具示例,展示了您需要做什么:
lineProducingActions :: [IO String]
lineProducingActions = replicate 10 getLine
wrongOrder, correctOrder :: IO ()
wrongOrder = do
xs <- sequence lineProducingActions
mapM_ putStrLn xs
correctOrder = do
let xs = [x >>= putStrLn | x <- lineProducingActions]
sequence_ xs
請注意,您可以在獲得所需排序的同時解耦生產者和消費者。您只需要避免在生產者中組合 I/O 操作。I/O 操作是可以像任何其他值一樣操作的純值。它們不是在撰寫時立即發生的副作用運算式。相反,它們以您將它們粘合在一起的任何順序發生。
uj5u.com熱心網友回復:
您需要使用unsafeInterleaveIO來安排您IO以后的一些操作。請注意,這些IO操作可能會以與您最初預期不同的順序執行!
但是,我強烈建議不要這樣做。更改您的IO [String]操作以在生成時列印每一行。
或者,如果您真的想維護計算即管道視圖,請查看 Hackage 上提供的眾多流媒體庫之一(streamly、管道、迭代器、管道、機器,以及其他六種)。
uj5u.com熱心網友回復:
感謝@benrg 的回答,我能夠使用以下代碼解決問題:
ed :: [EdCmdLine] -> [IO EdLines]
ed cmds = map (>>= return . toLines . head) $ edHistIO where
toLines :: EdState -> EdLines
toLines r = fromEd r [" "]
edHistIO = edRec defHs cmds (return [initState])
edRec :: [HandleHandler] -> [EdCmdLine] -> IO EdHistory -> [IO EdHistory]
edRec _ [] hist = [hist] -- if CTRL D
edRec defHs (cmd:cmds) hist = let next = edLine defHs cmd hist in next : edRec defHs cmds next
main = getContents >>= mapM_ (>>= (putStr . unlines)) . ed . lines
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/363877.html
標籤:哈斯克尔
下一篇:如何手動評估我的多功能?
