这可能是一个愚蠢的问题,但我无法在任何地方找到答案.我是一个Haskell新手,我遇到了I/O问题.
我有这个结构:
data SrcFile = SrcFile (IO Handle) String
srcFileHandle :: SrcFile -> IO Handle
srcFileHandle (SrcFile handle _) = handle
srcFileLine :: SrcFile -> String
srcFileLine (SrcFile _ string) = string
Run Code Online (Sandbox Code Playgroud)
现在的问题是我不知道如何将stdin/stderr/stdout分配给它,因为stdin等是Handler,没有IO处理程序.如果我使结构具有IO Handle的Handle属性,那么我将无法在其中添加任何其他文件句柄.
从您的定义来看SrcFile,似乎您可能正在尝试在Haskell中编写C程序.语言塑造了我们思考的方式,而好消息是Haskell是一种更强大的语言!
优秀的书籍Real World Haskell有一个关于懒惰I/O的部分.考虑摘录:
接近I/O的一种新方法是hGetContents函数.
hGetContents有类型Handle -> IO String.在String它返回代表所有通过手柄给出的文件中的数据.在严格评估的语言中,使用这样的函数通常是个坏主意.读取2KB文件的全部内容可能没什么问题,但如果您尝试读取500GB文件的全部内容,则可能会因为缺少RAM来存储所有数据而崩溃.在这些语言中,传统上使用循环等机制来处理文件的整个数据.
这是激进的部分.
但是
hGetContents不同.在String它的回报是懒洋洋地评估.在你打电话的那一刻hGetContents,实际上什么都没有读过.仅Handle在处理列表的元素(字符)时读取数据.由于String不再使用它的元素,Haskell的垃圾收集器会自动释放内存.所有这一切都完全透明地发生在你身上.既然你看起来像 - 而且,真的是纯粹的String,你可以把它传递给纯(非IO)代码.
再往下是一个部分readFile,writeFile它向您展示如何完全忘记句柄.
例如,假设您import要从源文件中获取所有行:
module Main where
import Control.Monad (liftM, mapM_)
import Data.List (isPrefixOf)
import System.Environment (getArgs, getProgName)
import System.IO (hPutStrLn, stderr)
main :: IO ()
main = getArgs >>= go
where go [path] = collectImports `liftM` readFile path >>= mapM_ putStrLn
go _ = getProgName >>=
hPutStrLn stderr . ("Usage: " ++) . (++ " source-file")
collectImports :: String -> [String]
collectImports = filter ("import" `isPrefixOf`)
. takeWhile (\l -> null l
|| "module" `isPrefixOf` l
|| "import" `isPrefixOf` l)
. lines
Run Code Online (Sandbox Code Playgroud)
即使main使用的定义readFile,程序只根据需要读取所命名的源文件,而不是整个事情!没有任何魔法可言:请注意,collectImports用于takeWhile仅检查它需要的那些线,而不是,例如,filter必须读取所有线.
当馈送自己的源时,程序输出
import Control.Monad (liftM, mapM_)
import Data.List (isPrefixOf)
import System.Environment (getArgs, getProgName)
import System.IO (hPutStrLn, stderr)
Run Code Online (Sandbox Code Playgroud)
所以拥抱懒惰.懒惰是你的朋友!享受Haskell的精彩之旅.
| 归档时间: |
|
| 查看次数: |
1134 次 |
| 最近记录: |