i'm trying to read from file in haskell and process every line
what i have now
main = interact (unlines . (map calculate) . lines)
this let me get every line from input and send it to calculate
now i want to get every line from a file and send it to calculate
this is what i tried
main = do
text <- readFile "input.txt"
let linii = lines text
interact (unlines . (map calculate) . linii)
tell me please how is it correct?
UPDATE below
calculate :: String -> String
calculate s=
case ret of
Left e -> "error: " ++(show e)
Right n -> "answer: " ++ (show n)
where
ret = parse parseInput "" s
main :: IO()
--main = interact (unlines . (map calculate) . lines)
main = do text <- readFile "input.txt"
let linii = lines
putStrLn . unlines $ map calculate linii
Remember that interact takes input from stdin and sends output to stdout. Since you have already read input from a file, you don't need the former. You only need to do the later. You can print a String with putStrln. Putting this all together, change
interact (unlines . (map calculate) . linii)
to
putStrLn . unlines $ map calculate linii
Related
After performing a string permutation with
listofstrings= ["string1", "string2", "string3", "string4"]
listsWithNewLines = map (++ ["\n"]) $ permutations listofstrings
mapM_ putStr (concat listsWithNewLines)
The output is very fine.
I would like to save the output to a textfile.
How could that work?
To "loop" over a list and perform monadic actions, you can use
foo = do
...
let action string = do
writeFile "filename" string
putStrLn ("written: " ++ string)
...
mapM_ action $ concat listsWithNewLines
or, with Data.Foldable, you can follow this idiom:
foo = do
...
for_ (concat listsWithNewLines) $ \string -> do
writeFile "filename" string
putStrLn ("written: " ++ string)
...
One solution could be changing your last line to:
mapM_ (writeFile "filename") $ concat listsWithNewLines
writeFile takes a file path and writes to it the string passed as a second argument.
UPDATE:
Instead of using writeFile, you can use appendFile (if not, the file would be overwritten every time a new word is put):
let writeAndPrint word = appendFile "filename" word >> putStr word
mapM_ writeAndPrint $ concat listsWithNewLines
>> is the operator of sequencing monadic computations. As #chi pointed out, you can rewrite this in a Haskell file, let's say, printAndWrite.hs as follows:
main = do
let listofstrings= ["string1", "string2", "string3", "string4"]
let listsWithNewLines = map (++ ["\n"]) $ permutations listofstrings
let writeAndPrint word = do
appendFile "filename" word
putStr word
mapM_ writeAndPrint $ concat listsWithNewLines
After this, you can either load it into GHCi, or compile the program using GHC and executing it on the console. If you load it in GHCi, you should use :load printAndWrite.hs and then run main.
Imagine I read an input block via stdin that looks like this:
3
12
16
19
The first number is the number of following rows. I have to process these numbers via a function and report the results separated by a space.
So I wrote this main function:
main = do
num <- readLn
putStrLn $ intercalate " " [ show $ myFunc $ read getLine | c <- [1..num]]
Of course that function doesn't compile because of the read getLine.
But what is the correct (read: the Haskell way) way to do this properly? Is it even possible to write this function as a one-liner?
Is it even possible to write this function as a one-liner?
Well, it is, and it's kind of concise, but see for yourself:
main = interact $ unwords . map (show . myFunc . read) . drop 1 . lines
So, how does this work?
interact :: (String -> String) -> IO () takes all contents from STDIN, passes it through the given function, and prints the output.
We use unwords . map (show . myFunc . read) . drop 1 . lines :: String -> String:
lines :: String -> [String] breaks a string at line ends.
drop 1 removes the first line, as we don't actually need the number of lines.
map (show . myFunc . read) converts each String to the correct type, uses myFunc, and then converts it back to a `String.
unwords is basically the same as intercalate " ".
However, keep in mind that interact isn't very GHCi friendly.
You can build a list of monadic actions with <$> (or fmap) and execute them all with sequence.
λ intercalate " " <$> sequence [show . (2*) . read <$> getLine | _ <- [1..4]]
1
2
3
4
"2 4 6 8"
Is it even possible to write this function as a one-liner?
Sure, but there is a problem with the last line of your main function. Because you're trying to apply intercalate " " to
[ show $ myFunc $ read getLine | c <- [1..num]]
I'm guessing you expect the latter to have type [String], but it is in fact not a well-typed expression. How can that be fixed? Let's first define
getOneInt :: IO Int
getOneInt = read <$> getLine
for convenience (we'll be using it multiple times in our code). Now, what you meant is probably something like
[ show . myFunc <$> getOneInt | c <- [1..num]]
which, if the type of myFunc aligns with the rest, has type [IO String]. You can then pass that to sequence in order to get a value of type IO [String] instead. Finally, you can "pass" that (using =<<) to
putStrLn . intercalate " "
in order to get the desired one-liner:
import Control.Monad ( replicateM )
import Data.List ( intercalate )
main :: IO ()
main = do
num <- getOneInt
putStrLn . intercalate " " =<< sequence [ show . myFunc <$> getOneInt | c <- [1..num]]
where
myFunc = (* 3) -- for example
getOneInt :: IO Int
getOneInt = read <$> getLine
In GHCi:
λ> main
3
45
23
1
135 69 3
Is the code idiomatic and readable, though? Not so much, in my opinion...
[...] what is the correct (read: the Haskell way) way to do this properly?
There is no "correct" way of doing it, but the following just feels more natural and readable to me:
import Control.Monad ( replicateM )
import Data.List ( intercalate )
main :: IO ()
main = do
n <- getOneInt
ns <- replicateM n getOneInt
putStrLn $ intercalate " " $ map (show . myFunc) ns
where
myFunc = (* 3) -- replace by your own function
getOneInt :: IO Int
getOneInt = read <$> getLine
Alternatively, if you want to eschew the do notation:
main =
getOneInt >>=
flip replicateM getOneInt >>=
putStrLn . intercalate " " . map (show . myFunc)
where
myFunc = (* 3) -- replace by your own function
I am trying to make a webpage that will list the contents of a given directory, but I am running into a strange problem: The code produces the desired output when I run it line by line in GHCi, but when it is executed in the running Scotty instance, it produces different (wrong) output. Here is the relevant part of the code:
serveDir :: String -> ActionM ()
serveDir p = do let path = prefix ++ p
entries <- liftIO $ getDirectoryContents path
fs <- liftIO $ filterM (doesFileExist . ((++) prefix)) entries
ds <- liftIO $ filterM (doesDirectoryExist . ((++) prefix)) entries
liftIO $ print path >> print entries >> print fs >> print ds
blaze $ renderDir fs ds
where prefix = "static/"
(that last line in the do statement just renders it into html. this works, but the correct output never makes it to that function)
When I run each line of this function in GHCi, i get the following output:
*Main> entries <- getDirectoryContents "static/stuff"
*Main> fs <- liftIO $ filterM (doesFileExist . ((++) "static/stuff/")) entries
*Main> ds <- liftIO $ filterM (doesDirectoryExist . ((++) "static/stuff/")) entries
*Main> liftIO $ print entries >> print fs >> print ds
["..","hello","bye","someDir","."]
["hello","bye"]
["..","someDir","."]
which is what I am expecting. But when this function is run from Scotty, called as serveDir "stuff/", I get this output:
"static/stuff/"
["..","hello","bye","someDir","."]
[]
["..","."]
What is happening here? I know that ActionM is an instance of MonadIO, otherwise this would not compile. I am at a bit of a loss. Can somebody shed some light on this or advise? Rest of code available upon request, but I can say that I am using wai-middleware-static to allow static file requests, and other file request from this directory in other functions works.
fs <- liftIO $ filterM (doesFileExist . ((++) prefix)) entries
Should that not be (++) path?
I am going through 'learn you some haskell' and I have written following application:
import System.IO
main = do
filename <- getLine
handle <- openFile filename ReadMode
content <- hGetContents handle
putStr . unlines . (map isLong) . lines $ content
hClose handle
isLong :: String -> String
isLong x = if length x > 10 then x ++ " long enough" else x ++ " could be better!"
And it works but when I remove "$" between lines and content a compilation fails.
Could you help me understand why this is wrong?
I was thinking that I compose statements with dots and I get a function (String -> IO ()) and I apply it to the "content" but why is "$" needed here?.
Thanks!
The operator (.) has type (b -> c) -> (a -> b) -> a -> c.... Its first two inputs must be functions.
lines content, however, is of type [String], not a function, hence f . lines content will fail. The compiler treats it as
f . (lines content)
By adding the ($), you change the precedence, and it becomes
f . lines $ content = (f . lines) $ content
which works, because f and lines are both functions.
The dollar sign in haskell is used for application of a function on a value.
Its backround is, that you do not need complicated parentheses in terms.
At the moment, I have this code in and around main:
import Control.Monad
import Control.Applicative
binSearch :: Ord a => [a] -> a -> Maybe Int
main = do
xs <- lines <$> readFile "Cars1.txt"
x <- getLine <* putStr "Registration: " -- Right?
putStrLn $ case binSearch xs x of
Just n -> "Found at position " ++ show n
Nothing -> "Not found"
My hope is for “Registration: ” to be printed, then for the program to wait for the input to x. Does what I've written imply that that will be the case? Do I need the <*, or will putting the putStr expression on the line above make things work as well?
PS: I know I have to convert binSearch to work with arrays rather than lists (otherwise it's probably not worth doing a binary search), but that's a problem for another day.
The line
x <- getLine <* putStr "Registration: "
orders the IO actions left-to-right: first a line is taken as input, then the message is printed, and finally variable x is bound to the result of getLine.
Do I need the <*, or will putting the putStr expression on the line
above make things work as well?
If you want the message to precede the input, you have to put the putStr on the line above, as follows:
main :: IO ()
main = do
xs <- lines <$> readFile "Cars1.txt"
putStr "Registration: "
x <- getLine
putStrLn $ case binSearch xs x of
Just n -> "Found at position " ++ show n
Nothing -> "Not found"
Alternatively,
x <- putStr "Registration: " *> getLine
or
x <- putStr "Registration: " >> getLine
would work, but they are less readable.
Finally, since you added the lazy-evaluation tag, let me add that your question is actually not about laziness, but about how the operator <* is defined, and in particular about the order in which it sequences the IO actions.