haskell readFile from file line by line - haskell

Haskell programming
how to use readFile
I use getLine but it should react with a user for each command
But i need to read lines from text file and process the input line
text <- readFile "input.txt"
let linii = lines text
interact (unlines . (map calculate) . linii)

So interact is to do IO using stdin and stdout. If instead of stdin you want to use a file for input, that's fine you can use the readFile function as you are already doing:
applyOnFileLines :: FilePath -> (String -> String) -> IO ()
applyOnFileLines filePath func = do
file <- readFile filePath
putStr . unlines
. map func
. lines
$ file

Related

Is it possible to have messages with multiple lines in translation files of Yesod?

I am doing i18n in a Yesod scaffolded application as instructed in the following links: https://github.com/yesodweb/yesod/wiki/i18n-messages-in-the-scaffolding, https://www.yesodweb.com/book/internationalization and http://haddock.stackage.org/nightly-2016-04-19/shakespeare-2.0.8.1/Text-Shakespeare-I18N.html
It looks like an en.msg file like:
Hello: Hello World!
MultilineText:
line 1.
line 2.
etc...
SingleLine: A single line message.
is not supprted, because of the MultilineText definition. Is this true or there is a way/syntax to do this?
Judging from the source, no, it is not possible:
loadLangFile :: FilePath -> IO [Def]
loadLangFile file = do
bs <- S.readFile file
let s = unpack $ decodeUtf8 bs
defs <- fmap catMaybes $ mapM (parseDef . T.unpack . T.strip . T.pack) $ lines s
return defs
The parseDef function operates on the result of lines call, which splits the file contents by newline character.

How do I pipe the output string produced by readFile "filename.txt" to Haskell's words function as an argument?

from the ghci> prompt, I would like to readFile "filename.text" and pass the produced string as an argument to the words function to convert sentences to wordlists.
Thanks
You can execute your pure function (words) "inside" the IO monad returned by readFile.
readFile :: FilePath -> IO String
and
words :: String -> [String]
so you can simply do
fmap words $ readFile "filename.txt"
which has the type IO [String]. If you do this in ghci (which is itself "inside" of an IO monad) you will get the word list displayed.
EDIT:
If you want to apply multiple transformations you may want to cleanly separate the pure part (based on #Davislor's solution from comments):
readFile "filename.txt" >>= (return . sort . words) >>= mapM_ putStrLn
The return here just lift to IO, you could simply replace return with mapM_ putStrLn instead (sorter, but less clean distinction).
Another solutions may be applicative style:
sort <$> words <$> readFile "filename.txt" >>= mapM_ putStrLn
or using do notation (imperative style):
do ; f <- readFile "filename.txt"; let out = sort (words f) in mapM_ putStrLn out
(which is ugly because I used ; instead of newline) or simply (less imperatively :) :
do ; f <- readFile "filename.txt"; mapM_ putStrLn $ sort $ words f

conditional standard handle redirection in Haskell

I want to read a file, process it, and write the results to another file; the input file name is to be supplied through a console argument, and the output file name is generated from the input file name.
The catch is I want it to transparently “fail over” to stdin/stdout if no arguments are supplied; essentially, in case a file name is supplied, I redirect stdin/stdout to the respective file names so I can transparently use interact whether the file name was supplied or not.
Here's the code hacked together with dummy output in a superfluous else. What will be the proper, idiomatic form of doing it?
It probably could have something to do with Control.Monad's when or guard, as was pointed out in a similar question, but maybe somebody wrote this already.
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)
There's nothing very special about interact - here is its definition:
interact :: (String -> String) -> IO ()
interact f = do s <- getContents
putStr (f s)
How about something like this:
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
Based on the command line arguments we set reader and writer to the IO-actions which will read the input and write the output.
This seems fairly idiomatic to me already. The one note I have is to avoid head, as it is an unsafe function (it can throw a runtime error). In this case it is fairly easy to do so by using case to pattern match.
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)

Read file with UTF-8 in Haskell as IO String

I have the following code which works fine unless the file has utf-8 characteres :
module Main where
import Ref
main = do
text <- getLine
theInput <- readFile text
writeFile ("a"++text) (unlist . proc . lines $ theInput)
With utf-8 characteres I get this:
hGetContents: invalid argument (invalid byte sequence)
Since the file I'm working with has UTF-8 characters, I would like to handle this exception in order to reuse the functions imported from Ref if possible.
Is there a way to read a UTF-8 file as IO String so I can reuse my Ref's functions?. What modifications should I make to my code?. Thanks in Advance.
I attach the functions declarations from my Ref module:
unlist :: [String] -> String
proc :: [String] -> [String]
from prelude:
lines :: String -> [String]
This can be done with just GHC's basic (but extended from the standard) System.IO module, although you'll then have to use more functions:
module Main where
import Ref
import System.IO
main = do
text <- getLine
inputHandle <- openFile text ReadMode
hSetEncoding inputHandle utf8
theInput <- hGetContents inputHandle
outputHandle <- openFile ("a"++text) WriteMode
hSetEncoding outputHandle utf8
hPutStr outputHandle (unlist . proc . lines $ theInput)
hClose outputHandle -- I guess this one is optional in this case.
Thanks for the answers, but I found the solution by myself.
Actually the file I was working with has this codification:
ISO-8859 text, with CR line terminators
So to work with that file with my haskell code It should have this codification instead:
UTF-8 Unicode text, with CR line terminators
You can check the file codification with the utility file like this:
$ file filename
To change the file codification follow the instructions from this link!
Use System.IO.Encoding.
The lack of unicode support is a well known problem with with the standard Haskell IO library.
module Main where
import Prelude hiding (readFile, getLine, writeFile)
import System.IO.Encoding
import Data.Encoding.UTF8
main = do
let ?enc = UTF8
text <- getLine
theInput <- readFile text
writeFile ("a" ++ text) (unlist . proc . lines $ theInput)

cat emulator in Haskell

So I'm attempting to make a program that reads from a handle and writes to stdOut, like so:
import IO
import System
cat w = do
fromHandle <- getAndOpenFile w ReadMode
contents <- hGetContents fromHandle
putStr contents
putStr "Done."
getAndOpenFile :: String -> IOMode -> IO Handle
getAndOpenFile name mode =
do
catch (openFile name mode)
(\_ -> do
putStrLn ("Cannot open "++ name ++"\n")
return())
I'm fairly new to Hs and it seems like this should be far more simple than I'm making it for myself. Any suggestions to helping me move further?
the usage would be ./cat "foo.txt" and would print the text in the foo.txt file to stdOut.
There is the below function which does what you want.
readFile :: FilePath -> IO String
use this with putStr to print the IO String

Resources