2016-07-09 32 views
1

Ich möchte eine Datei lesen, verarbeiten und die Ergebnisse in eine andere Datei schreiben; Der Name der Eingabedatei muss über ein Konsolenargument angegeben werden. Der Name der Ausgabedatei wird aus dem Namen der Eingabedatei generiert.bedingte Standard-Handle-Umleitung in Haskell

Der Haken ist, ich will es transparent "fail over" zu stdin/stdout, wenn keine Argumente geliefert werden; Im Wesentlichen, falls ein Dateiname angegeben wird, leite ich stdin/stdout zu den entsprechenden Dateinamen um, so dass ich interact transparent verwenden kann, egal ob der Dateiname angegeben wurde oder nicht.

Hier ist der Code zusammen mit Dummy-Ausgang in einem überflüssigen else gehackt. Was wird die richtige, idiomatische Form sein, es zu tun?

Es könnte wahrscheinlich etwas mit Control.Monad ist zu tun, wenn oder Wache, wie es in einer ähnlichen Frage erwähnt, aber vielleicht jemand schon schrieb.

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) 

Antwort

1

Es gibt nichts ganz Besonderes interact - hier ist seine Definition:

interact  :: (String -> String) -> IO() 
interact f  = do s <- getContents 
         putStr (f s) 

Wie wäre es damit so etwas wie:

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 

auf den Zeilenbefehl Basierend Argumente, die wir gesetzt reader und writer zu den IO-Aktionen, die die Eingabe lesen und die Ausgabe schreiben.

+0

Vielen Dank für Entzuckerung 'interagieren ', hätte eigentlich gedacht, es zu tun, dieser Code löst das Problem auf jeden Fall, und es ist auch portabler (' hDuplicateTo' ist GHC-spezifisch, es fehlt im Haskell Report von 2010). – yvs314

1

Dies scheint ziemlich idiomatischen mir schon. Die einzige Notiz, die ich habe, ist head zu vermeiden, da es eine unsichere Funktion ist (es kann einen Laufzeitfehler verursachen). In diesem Fall ist es ziemlich einfach, dies zu tun, indem Sie case zum Mustervergleich verwenden.

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) 
+0

die 'print„Arbeit durch stdin/redirect' Stück nur eine Art ** ist nop ** Betrieb zu mir, die Frage war, wie würde ich es ganz zu vermeiden. – yvs314