Stdin作为IO句柄

Arg*_*Arg 4 haskell

这可能是一个愚蠢的问题,但我无法在任何地方找到答案.我是一个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属性,那么我将无法在其中添加任何其他文件句柄.

Gre*_*con 6

从您的定义来看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的精彩之旅.