First Haskell IO program isn't working - haskell

Sorry, this is probably really dumb, but can someone explain me why this program doesn't compile? I get Couldn't match expected type 'a1 -> String' with actual type 'IO String'.
import System.Environment
main = do
[first, last] <- getArgs
firstnames <- lines . readFile "firstnames_male"
lastnames <- lines . readFile "lastnames"
print firstnames

You can't do lines . readFile "lastnames".
The readFile function returns an IO String, not a String.
You can, however, use the fmap function (or the <$> operator) to achieve this:
main = do
[first, last] <- argArgs
firstnames <- lines `fmap` readFile "firstnames_males"
...
This works because IO is a functor.

Related

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

Read a single int from a file and print it

How do I create a program that reads a line from a file, parse it to an int and print it(ignoring exceptions of course). Is there anything like "read" but for IO String?
I've got this so far but I couldn't get around the IO types:
readFromFile = do
inputFile <- openFile "catalogue.txt" ReadMode
isbn <- read( hGetLine inputFile)
hClose inputFile
You can specify the type explicitly, change the read line to
isbn <- fmap read (hGetLine inputFile) :: IO Int
As hGetLine inputFile is of type IO String, you should use fmap to get "inside" to read as an Int.
You can use the readFile function to convert your file to a string.
main = do
contents <- readFile "theFile"
let value = read $ head $ lines contents::Int
print value
You should add better error detection, or this program will fail if there isn't a first line, or if the value is malformed, but this is the basic flow....
First, observe that reading stuff and then immediately printing it can result in mysterious errors:
GHCi, version 8.0.0.20160421: http://www.haskell.org/ghc/ :? for help
Prelude λ read "123"
*** Exception: Prelude.read: no parse
The reason is that you don't specify what type you want to read. You can counter this by using type annotations:
Prelude λ read "123" :: Integer
123
but it is sometimes easier to introduce a little helper function:
Prelude λ let readInteger = read :: String -> Integer
Prelude λ readInteger "123"
123
Now to the main problem. read( hGetLine inputFile) doesn't work because hGetLine inputFile returns and IO String and read needs a String. This can be solved in two steps:
line <- hGetLine inputFile
let isbn = readInteger line
Note two different constructs <- and let .. =, they do different things. Can you figure out exactly what?
As shown in another answer, you can do it in a less verbose manner:
isbn <- fmap readInteger (hGetLine inputFile)
which is great if you do a simple thing like read. But it is often desirable to explicitly name intermediate results. You can use <- and let .. = constructs in such cases.

how to parse a uniprot-file with parsec?

I am a newbie to Haskell, but it seems like a powerful language that I want to learn. I was adopting some code from the chapter in real world Haskell on parsec. I tried to make my own version of it parsing the content of a uniprot-file. This is a file that consists of records (that starts with ">"), and where each record consists of lines. My code seems very close to what is done in the example, but I am getting a lot of errors - mostly on types. My exception is among other that I am taking the output of readFile (IO string) instead of a string. I would appreciate it if someone could help me understand what is wrong in my approach...
import Text.ParserCombinators.Parsec
main:: IO()
parseSprot :: IO String -> Either ParseError [[String]]
parseSprot input = parse uniprotFile "(unknown)" input
where
uniprotFile = endBy record eol
record = sepBy lines (char '>')
lines = many (noneOf ",\n")
eol = char '\n'
main = do
parseSprot $ readFile "uniprot_sprot.fasta"
putStrLn "hey"
parseSprot doesn't need an IO in its signature.
parseSprot :: String -> Either ParseError [[String]]
...
The result of readFile is an IO String. You can do something with this String by binding the result of the readFile action into a new IO action. In do notation you can bind the result to a variable with <-
main = do
fileContents <- readFile "uniprot_sprot.fasta"
The parseSprot function doesn't return a result in IO, you can use it anywhere. In do notation we tell the difference between a result bound to a variable and a declaration by using different syntax. x <- ... binds a result to a variable. let x = ... declares x to be whatever is on the right hand side.
main = do
fileContents <- readFile "uniprot_sprot.fasta"
let parsedContents = parseSprot fileContents
To test what your parser is doing, you might want to print the value returned from parse.
main = do
fileContents <- readFile "uniprot_sprot.fasta"
let parsedContents = parseSprot fileContents
print parsedContents
Without do notation you can write this as
main = readFile "uniprot_sprot.fasta" >>= print . parseSprot
>>= takes the result of the first computation and feeds it into a function to decide what to do next.

Picking a random line from a file in Haskell

I am trying to have Haskell pick a random line from a file and print it. My attempt is below:
import Data.Random.Extras (choice)
main :: IO ()
main = do
filecontents <- readFile "wordlist.txt"
let words = lines filecontents
let word = choice $ words
word >>= putStrLn
The last line is where the error occurs. >>= expects an IO String, but word is a Data.RVar.RVar String. (The variable is called `word' because each line should be one word.)
I have read the docs for RVar but after some hacking, I do not see how to solve my problem. Any ideas?
I am using ghc 7.6.3 from an installation of the Haskell Platform, OS X 10.9.
The complete error is below:
[ 01:46 PM (51) integral:thoth ~/Source/pwgen ] > ghc -o pwgen pwgen.hs
[1 of 1] Compiling Main ( pwgen.hs, pwgen.o )
pwgen.hs:40:3:
Couldn't match type `Data.RVar.RVarT
Data.Functor.Identity.Identity'
with `IO'
Expected type: IO String
Actual type: Data.RVar.RVar String
In the first argument of `(>>=)', namely `word'
In a stmt of a 'do' block: word >>= putStrLn
In the expression:
do { filecontents <- readFile "wordlist.txt";
let words = lines filecontents;
let word = choice $ words;
word >>= putStrLn }
Finally, I am aware that there are more efficient ways to pick a random line from a file. I'm just going for the bare minimum that works. I am also very much a Haskell beginner and may have some fundamental misconceptions, especially regarding IO and monads.
You can use
import Data.Random
and then modify main
main = do
...
let word = sample $ choice words
putStrLn =<< word
This works because when you import Data.Random it contains an instance of MonadRandom for IO and gives you sample as a convenient wrapper for runRVar with a generator obtained from the IO monad.

Using mapM f [list] where f is defined with do notation

I currently have this code which will perform the main' function on each of the filenames in the list files.
Ideally I have been trying to combine main and main' but I haven't made much progress. Is there a better way to simplify this or will I need to keep them separate?
{- Start here -}
main :: IO [()]
main = do
files <- getArgs
mapM main' files
{- Main's helper function -}
main' :: FilePath -> IO ()
main' file = do
contents <- readFile file
case (runParser parser 0 file $ lexer contents) of Left err -> print err
Right xs -> putStr xs
Thanks!
Edit: As most of you are suggesting; I was trying a lambda abstraction for this but wasn't getting it right. - Should've specified this above. With the examples I see this better.
The Control.Monad library defines the function forM which is mapM is reverse arguments. That makes it easier to use in your situation, i.e.
main :: IO ()
main = do
files <- getArgs
forM_ files $ \file -> do
contents <- readFile file
case (runParser f 0 file $ lexer contents) of
Left err -> print err
Right xs -> putStr xs
The version with the underscore at the end of the name is used when you are not interested in the resulting list (like in this case), so main can simply have the type IO (). (mapM has a similar variant called mapM_).
You can use forM, which equals flip mapM, i.e. mapM with its arguments flipped, like this:
forM_ files $ \file -> do
contents <- readFile file
...
Also notice that I used forM_ instead of forM. This is more efficient when you are not interested in the result of the computation.

Resources