Haskell 中的条件标准句柄重定向
conditional standard handle redirection in Haskell
我想读取一个文件,处理它,并将结果写入另一个文件;输入文件名将通过控制台参数提供,输出文件名从输入文件名生成。
问题是如果没有提供任何参数,我希望它透明地“故障转移”到 stdin/stdout;本质上,如果提供了文件名,我将 stdin/stdout 重定向到相应的文件名,这样无论是否提供文件名,我都可以透明地使用 interact。
这是在多余的 else 中与虚拟输出一起破解的代码。这样做的正确、惯用的形式是什么?
它可能与 Control.Monad 的 when 或 guard 有关,正如在类似的问题,但也许有人已经写过了。
import System.IO
import Data.Char(toUpper)
import System.Environment
import GHC.IO.Handle
main :: IO ()
main = do
args <- getArgs
if(not $ null args) then
do
print $ "working with "++ (head args)
finHandle <- openFile (head args) ReadMode --open the supplied input file
hDuplicateTo finHandle stdin --bind stdin to finName's handle
foutHandle <- openFile ((head args) ++ ".out") WriteMode --open the output file for writing
hDuplicateTo foutHandle stdout --bind stdout to the outgoing file
else print "working through stdin/redirect" --get to know
interact ((++) "Here you go---\n" . map toUpper)
这对我来说已经相当地道了。我有一个注意事项是避免 head
,因为它是一个不安全的函数(它会引发运行时错误)。在这种情况下,通过使用 case
进行模式匹配很容易做到这一点。
main :: IO ()
main = do
args <- getArgs
case args of
fname:_ -> do
print $ "working with " ++ fname
finHandle <- openFile fname ReadMode
hDuplicateTo finHandle stdin
foutHandle <- openFile (fname ++ ".out") WriteMode
hDuplicateTo foutHandle stdout
[] -> do
print "working through stdin/redirect"
interact ((++) "Here you go---\n" . map toUpper)
interact
没有什么特别之处 - 这是它的定义:
interact :: (String -> String) -> IO ()
interact f = do s <- getContents
putStr (f s)
这样的事情怎么样:
import System.Environment
import Data.Char
main = do
args <- getArgs
let (reader, writer) =
case args of
[] -> (getContents, putStr)
(path : _) -> let outpath = path ++ ".output"
in (readFile path, writeFile outpath)
contents <- reader
writer (process contents)
process :: String -> String
process = (++) "Here you go---\n" . map toUpper
根据命令行参数,我们将 reader
和 writer
设置为将读取输入并写入输出的 IO 操作。
我想读取一个文件,处理它,并将结果写入另一个文件;输入文件名将通过控制台参数提供,输出文件名从输入文件名生成。
问题是如果没有提供任何参数,我希望它透明地“故障转移”到 stdin/stdout;本质上,如果提供了文件名,我将 stdin/stdout 重定向到相应的文件名,这样无论是否提供文件名,我都可以透明地使用 interact。
这是在多余的 else 中与虚拟输出一起破解的代码。这样做的正确、惯用的形式是什么?
它可能与 Control.Monad 的 when 或 guard 有关,正如在类似的问题,但也许有人已经写过了。
import System.IO
import Data.Char(toUpper)
import System.Environment
import GHC.IO.Handle
main :: IO ()
main = do
args <- getArgs
if(not $ null args) then
do
print $ "working with "++ (head args)
finHandle <- openFile (head args) ReadMode --open the supplied input file
hDuplicateTo finHandle stdin --bind stdin to finName's handle
foutHandle <- openFile ((head args) ++ ".out") WriteMode --open the output file for writing
hDuplicateTo foutHandle stdout --bind stdout to the outgoing file
else print "working through stdin/redirect" --get to know
interact ((++) "Here you go---\n" . map toUpper)
这对我来说已经相当地道了。我有一个注意事项是避免 head
,因为它是一个不安全的函数(它会引发运行时错误)。在这种情况下,通过使用 case
进行模式匹配很容易做到这一点。
main :: IO ()
main = do
args <- getArgs
case args of
fname:_ -> do
print $ "working with " ++ fname
finHandle <- openFile fname ReadMode
hDuplicateTo finHandle stdin
foutHandle <- openFile (fname ++ ".out") WriteMode
hDuplicateTo foutHandle stdout
[] -> do
print "working through stdin/redirect"
interact ((++) "Here you go---\n" . map toUpper)
interact
没有什么特别之处 - 这是它的定义:
interact :: (String -> String) -> IO ()
interact f = do s <- getContents
putStr (f s)
这样的事情怎么样:
import System.Environment
import Data.Char
main = do
args <- getArgs
let (reader, writer) =
case args of
[] -> (getContents, putStr)
(path : _) -> let outpath = path ++ ".output"
in (readFile path, writeFile outpath)
contents <- reader
writer (process contents)
process :: String -> String
process = (++) "Here you go---\n" . map toUpper
根据命令行参数,我们将 reader
和 writer
设置为将读取输入并写入输出的 IO 操作。