【问题标题】:conditional standard handle redirection in HaskellHaskell中的条件标准句柄重定向
【发布时间】:2016-07-09 16:53:00
【问题描述】:

我想读取一个文件,对其进行处理,然后将结果写入另一个文件;输入文件名将通过控制台参数提供,输出文件名由输入文件名生成。

如果没有提供参数,我希望它透明地“故障转移”到标准输入/标准输出;本质上,如果提供了文件名,我会将 stdin/stdout 重定向到相应的文件名,这样无论是否提供了文件名,我都可以透明地使用 interact

这里的代码在多余的 else 中与虚拟输出一起被破解。什么是正确的、惯用的做法?

这可能与 Control.Monad 的 whenguard 有关,正如在类似问题中指出的那样,但也许有人已经写过了。

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)

【问题讨论】:

    标签: haskell io monads io-redirection


    【解决方案1】:

    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
    

    根据命令行参数,我们将readerwriter 设置为将读取输入并写入输出的IO 操作。

    【讨论】:

    • 非常感谢您对interact 进行了脱糖处理,应该猜到可以直接完成,这段代码确实解决了手头的问题,而且它也更便携(hDuplicateTo 是 GHC 特有的,它在 2010 年的 Haskell 报告中没有出现)。
    【解决方案2】:

    这对我来说似乎已经很惯用了。我要注意的是避免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)
    

    【讨论】:

    • print "working through stdin/redirect 对我来说只是一种 nop 操作,问题是如何完全避免它。
    猜你喜欢
    • 2021-09-30
    • 2012-02-17
    • 1970-01-01
    • 1970-01-01
    • 2020-03-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-19
    相关资源
    最近更新 更多