Haskell: why I cant use liftM lines . getContents - haskell

I have getLinesIn = liftM lines . getContents than
readAndWriteIn = do
list <- getLinesIn
and it doesnt work.
It says: Couldn't match expected type a0 -> m0 String with actual type IO String.
I dont understand why is that?
When I use getLinesFile = liftM lines . readFile
It works fine.
I need to do the same with getContents. Is there a way?
Thanks for any ideas.
EDIT:
Full output:
Couldn't match expected type `a0 -> m0 String'
with actual type `IO String'
In the second argument of `(.)', namely `getContents'
In the expression: liftM lines . getContents
In an equation for `getLinesIn':
getLinesIn = liftM lines . getContents

readFile is a function FilePath -> IO String while getContents is just IO String so you cannot use the (.) operator to compose it with liftM lines. You should just use
getLinesIn = liftM lines getContents
or
getLinesIn = fmap lines getContents

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

First Haskell IO program isn't working

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.

Snap render list in Hamlet

Given this little project I'm using to learn Haskell, I would like to move my request handler's code generation to a Hamlet template, but am unsure how to pass things around.
My current code generates the following error when lines are uncommented, which is the first blocker:
Couldn't match expected type `String -> String'
with actual type `String'
In the return type of a call of `renderHtml'
Probable cause: `renderHtml' is applied to too many arguments
In the expression: renderHtml ($ (shamletFile "fileList.hamlet"))
In an equation for `myTemplate':
myTemplate = renderHtml ($ (shamletFile "fileList.hamlet"))
Code:
site :: Snap ()
site =
ifTop (writeBS "hello world") <|>
route [ ("foo", writeBS "ba"),
("view_root_json_files", listRootFilesHandler)
] <|>
dir "static" (serveDirectory ".")
--myTemplate :: String -> String
--myTemplate = renderHtml ( $(shamletFile "fileList.hamlet") )
toText :: [FilePath] -> Text
toText = foldMap (flip snoc '\n' . pack)
listRootFilesHandler :: Snap ()
listRootFilesHandler = do
filenames <- liftIO $ getDirectoryContents "data"
let filtered_filenames = filter (not . isPrefixOf ".") filenames
writeText $ toText filtered_filenames
Ghc is telling you the correct type signature to put there. Just replace String -> String with String.

IO Char array not usable in place of a String when using liftM

I have a function that I want to print out the value of. It isn't pure as it uses the values from some random functions, which I have already determined that they work correctly. My code is
getWord :: [IO Char]
getWord = getRandomConsonant:getRandomVowel:getRandomConsonant:getRandomConsonant: getRandomVowel:[]
main = do
liftM putStrLn getWord
I'm under the impression that liftM allows putStrLn to print the value of getWord, but it fails with the error:
word.hs:30:24:
Couldn't match type `IO Char' with `[Char]'
Expected type: [String]
Actual type: [IO Char]
In the second argument of `liftM', namely `getWord'
In a stmt of a 'do' block: liftM putStrLn getWord
In the expression: do { liftM putStrLn getWord }
As this doesn't work, is there any way to print out or execute an [IO Char]?
I understand that IO objects have to be "executed" in order to get the value from them, but I could not figure out a way to do it. If there is a blatant misunderstanding here, excuse me, as I have just started learning Haskell yesterday.
Be careful: [IO Char] is not IO [Char]
If you had something of type IO [Char] like return "hi", you could do:
(return "hi") >>= print
But because your type is [IO Char], which is a list of IO Char, you would have to do something like this:
sequence [(return 'h'), (return 'i')] >>= print

Haskell IO code doesn't typecheck

I'm a beginner with Haskell and am having trouble figuring out some code. What do I need to do to get the types right on this IO section of my code?
Thanks in advance.
loadPeople :: FilePath -> IO [Person]
loadPeople file = do
lines <- getLines file
map parsePerson lines
getLines :: FilePath -> IO [String]
getLines = liftM lines . readFile
parsePerson :: String -> Person
parsePerson line = ...........
map is underlined in red in Leksah, and the compile error I am receiving is:
src\Main.hs:13:3:
Couldn't match expected type `IO [Person]'
against inferred type `[Person]'
In the expression: map parsePerson lines
In the expression:
do { lines <- getLines file;
map parsePerson lines }
In the definition of `loadPeople':
loadPeople file
= do { lines <- getLines file;
map parsePerson lines }
map parsePerson lines has type [Person], but since you need the result type of loadPeople is IO [Person], you need to wrap it in IO using return:
return $ map parsePerson lines

Resources