Haskell --- error using SplitOn "," - haskell

getLines = liftM lines . readFile
main = do
argv <- getArgs
name <- getProgName
if not (null argv)
then do
let file = head argv
list <- getLines file
let olist = mergesort (<=) list
let splitter = splitOn "," olist
loop olist
else hPutStr stderr $ "usage: " ++ name ++ " filename"
loop a = do
line <- getLine
case line of
"help" -> putStrLn "print - prints list in alphabetical order\n\
\quit - exits program"
"print" -> do putStrLn "[print]"
mapM_ putStrLn a
putStr "\n"
"quit" -> do putStrLn "[quit]"
exitSuccess
_ -> putStrLn "invalid command"
loop a
I'm getting this error:
Couldn't match type '[Char]' with `Char'
Expected type: [Char]
Actual type: [String]
any tips?

You need to use single quotes for char constants.
See this
let splitter = splitOn ',' olist

Related

Haskell -- Main.hs:18:5: parse error on input ‘putStrLn’

module Main where
reportResults :: [String] -> [Int] -> IO ()
reportResults fileNames exitCodes = do
putStrLn "All Files"
putStrLn "---------"
putStr.unlines $ map (" " ++) fileNames
putStrLn ""
let problems = filter (\p -> fst p /= 0) $ zip exitCodes fileNames
putStrLn "Problematic Files"
putStrLn "-----------------"
mapM_ (putStrLn . showProblem) problems
where showProblem :: (Int, String) -> String
showProblem (c, f) = " " ++ show c ++ " - " ++ f
putStrLn "Done!" -- "Parse error on input...". OK if this line is removed.
main :: IO ()
main = do
let fileNames = ["A", "B", "C", "D"]
let exitCodes = [0, 1, 2, 3]
reportResults fileNames exitCodes
The code works fine if I comment out, or remove, the offending line (line 18), but I would really like to retain it and also understand what I'm doing wrong. After trying many permutations and searching heaps, I still can't crack it. Any help would be greatly appreciated.
You can define the showProblem function in a let clause, so:
reportResults :: [String] -> [Int] -> IO ()
reportResults fileNames exitCodes = do
putStrLn "All Files"
putStrLn "---------"
putStr.unlines $ map (" " ++) fileNames
putStrLn ""
let problems = filter (\p -> fst p /= 0) $ zip exitCodes fileNames
putStrLn "Problematic Files"
putStrLn "-----------------"
let showProblem (c, f) = " " ++ show c ++ " - " ++ f
mapM_ (putStrLn . showProblem) problems
putStrLn "Done!" -- "Parse error on input...". OK if this line is removed.

'getLine' not working as intended, being skipped

I am fairly new to Haskell and am writing some simple text/file manipulation functions. I am currently attempting to modify a string before adding it to a file.
I have a function 'insertChar' which adds a character at any given position in a string (using the solution of problem 21 from 99 problems in Haskell https://wiki.haskell.org/99_questions/21_to_28).
import System.Environment
import System.Directory
import System.IO
import Data.List
main :: IO ()
main = do
putStrLn "Insert a string"
word <- getLine
putStrLn "Insert a char"
char <- getChar
putStrLn "Insert a position"
pos <- getLine *line which is skipped*
let x = (read pos :: Int) *converts string into int*
putStrLn "Adding char to list..."
let newS = [(insertChar char word x)] *result of insertChar is set to
newS*
putStrLn "Printed list: "
print (newS) *print new string*
putStrLn "Insert file name"
file <- getLine
putStrLn "Adding new string to file..."
add file newS
insertChar :: a -> [a] -> Int -> [a]
insertChar x ys 1 = x:ys
insertChar x (y:ys) n = y:insertChar x ys (n-1)
add :: String -> [String] -> IO ()
add fileName [item] = appendFile fileName item
The user is asked to enter a string, then a character they wish to add to this string and finally the position in the string where they wish to add the character. I can input the string fine but when I press enter after inputting the character, the 'getLine' for inputting the position is skipped and the following error is produced;
GHCI>main
Insert a string
hello world
Insert a char
s
Insert a position
Adding char to list...
Printed list:
["*** Exception: Prelude.read: no parse
I have seen this stack overflow post; haskell -skipping getLine
and have attempted to follow that answer changing the code to;
import System.Environment
import System.Directory
import System.IO (hSetBuffering, stdin, BufferMode(NoBuffering)) *New line*
import Data.List
main :: IO ()
main = do
hSetBuffering stdin NoBuffering *New line*
putStrLn "Insert a string"
word <- getLine
putStrLn "Insert a char"
char <- getChar
putStrLn "Insert a position"
pos <- getLine
let x = (read pos :: Int)
putStrLn "Adding char to list..."
let newS = [(insertChar char word x)]
putStrLn "Printed list: "
print (newS)
putStrLn "Insert file name"
file <- getLine
putStrLn "Adding new string to file..."
add file newS
insertChar :: a -> [a] -> Int -> [a]
insertChar x ys 1 = x:ys
insertChar x (y:ys) n = y:insertChar x ys (n-1)
add :: String -> [String] -> IO ()
add fileName [item] = appendFile fileName item
However, it still produces the same error. Any clue what I am doing wrong?
Thanks to Willem Van Onsem's comment on my original question I have been able to find a solution. I added a "getLine" after the line 'putStrLn "Insert a position"' so the code now looks like;
import System.Environment
import System.Directory
import System.IO
import Data.List
main :: IO ()
main = do
putStrLn "Insert a string"
word <- getLine
putStrLn "Insert a char"
char <- getChar
putStrLn "Insert a position"
temp <- getLine *line that has been added*
pos <- getLine
let x = (read pos :: Int)
putStrLn "Adding char to list..."
let newS = [(insertChar char word x)]
putStrLn "Printed list: "
print (newS)
putStrLn "Insert file name"
file <- getLine
putStrLn "Adding new string to file..."
add file newS
insertChar :: a -> [a] -> Int -> [a]
insertChar x ys 1 = x:ys
insertChar x (y:ys) n = y:insertChar x ys (n-1)
add :: String -> [String] -> IO ()
add fileName [item] = appendFile fileName item
You imported the right stuff, but never actually called it! Try this:
main = do
hSetBuffering stdin NoBuffering
-- ...all the rest of your original main, exactly as it used to be
This way, when it gets to the getChar line, it will return from the getChar as soon as you press a key -- not wait until you press enter. The UI will make more sense, and the code will, too, because you don't need to swallow a phantom newline that the user didn't actually want to enter anyway.

How to fix writing a list content in a file

I have a function which contains a list. I want just to write that list content in a file from main after user input.
putTodo :: (Int, String) -> IO ()
putTodo (n, todo) = putStrLn (show n ++ ": " ++ todo)
prompt :: [String] -> IO ()
prompt todos = do
putStrLn "The list contains:"
mapM_ putTodo (zip [0..] todos)
putStrLn " "
command <- getLine
getCommand command todos
What I tried:
main = do
outh <- openFile "agenda.txt" WriteMode;
hPutStrLn outh prompt[]
-- hPutStrLn outh (show prompt[])
-- hPrint (show prompt[])
hClose outh;
Thank you.
Your code contains a couple of errors / problems:
prompt[] isn't valid (in main) - this should be prompt
hPutStrLn expects a String as its second argument, but you provide IO()
getCommand is not defined
What you need is:
a list of todos (possibly returned by a function)
a function that converts this list of todos to a string
hPutStrLn to print this string to the output file
Here's a simple version with a hard-coded list of todos (my Haskell isn't very advanced, so this could probably be done in a much more elegant way):
import System.IO
type Todo = (Int, String)
todoToString :: Todo -> String
todoToString (idx, name) = (show idx) ++ " : " ++ name
todosToString :: [Todo] -> String
todosToString todos = foldl (\acc t -> acc ++ "\n" ++ (todoToString t)) "" todos
allTodos :: [Todo]
allTodos = [(1, "Buy milk"), (2, "Program Haskell")]
main = do
outh <- openFile "agenda.txt" WriteMode;
hPutStrLn outh (todosToString allTodos);
hClose outh;

*** Exception: user error (Prelude.readIO: no parse) in haskell

I'm trying to write a program that loops all the time waiting for an input from the user but for some reason it doesn't loop.
My program is :
charAt :: String->Char->Int
main = do
x <- readLn
if x == 1
then do
putStrLn "Word: "
word <- getLine
putStrLn "Char: "
ch <- getChar
putStrLn (show (charAt word ch))
else print "Nothing"
main
But i actually get this error:
*** Exception: user error (Prelude.readIO: no parse)
If i remove the last main calling the program will work .
does anybody knows why is that happening?
When you use getChar, it will take only a single character from your stream. However, if you've entered AEnter, the newline character '\n' is still in your stdin. A '\n' cannot get parsed into an Int, therefore you end up with that error.
You can remove that newline if you call getLine afterwards:
ch <- getChar
putStrLn (show (charAt word ch))
_ <- getLine
Or you write your own helpers:
promptInt :: IO Int
promptInt = do
putStr "Int: "
line <- getLine
case readMaybe line of
Just x -> return x
_ -> putStrLn "Try again." >> promptInt
promptChar :: IO Char
promptChar = do
putStr "Char: "
line <- getLine
case line of
[x,_] -> return x
_ -> putStrLn "Try again." >> promptChar

Reading lines and reversing the text with Haskell

My program should do the following:
Read lines from a file
For each line, reverse the text of each word ("bat cat hat" becomes "tab tac tah")
Print out the the reverse text
But it doesn't work and being a Haskell-newbie, I can't understand the errors.
Here is my code:
main = do
content <- readFile "test.txt"
let linesList = lines content
reverseLines
reverseWords :: String -> String
reverseWords = unwords . map reverse . words
reverseLines :: [String] -> IO ()
reverseLines inputList = do
if null inputList
then return ()
else do
line <- inputList!!0
if null line
then return ()
else do
putStrLn $ reverseWords line
reverseLines . tail inputList
And my errors:
readlines.hs:4:9:
Couldn't match expected type `IO b0'
with actual type `[String] -> IO ()'
In a stmt of a 'do' block: reverseLines
In the expression:
do { content <- readFile "test.txt";
let linesList = lines content;
reverseLines }
In an equation for `main':
main
= do { content <- readFile "test.txt";
let linesList = ...;
reverseLines }
readlines.hs:14:25:
Couldn't match type `[Char]' with `IO [Char]'
Expected type: [IO [Char]]
Actual type: [String]
In the first argument of `(!!)', namely `inputList'
In a stmt of a 'do' block: line <- inputList !! 0
In the expression:
do { line <- inputList !! 0;
if null line then
return ()
else
do { putStrLn $ reverseWords line;
.... } }
readlines.hs:19:33:
Couldn't match expected type `IO ()' with actual type `a0 -> IO ()'
In a stmt of a 'do' block: reverseLines . tail inputList
In the expression:
do { putStrLn $ reverseWords line;
reverseLines . tail inputList }
In a stmt of a 'do' block:
if null line then
return ()
else
do { putStrLn $ reverseWords line;
reverseLines . tail inputList }
readlines.hs:19:48:
Couldn't match expected type `a0 -> [String]'
with actual type `[String]'
In the return type of a call of `tail'
Probable cause: `tail' is applied to too many arguments
In the second argument of `(.)', namely `tail inputList'
In a stmt of a 'do' block: reverseLines . tail inputList
Firstly, your last line in your main function is of type [String] -> IO (), and you need it to be IO (), so you actually need to pass it the list of strings. Here is one way to do what you are requesting:
main :: IO ()
main = do
content <- readFile "test.txt"
let linesList = lines content
reverseLines linesList
reverseWords :: String -> String
reverseWords = unwords . map reverse . words
reverseLines :: [String] -> IO ()
reverseLines = mapM_ (putStrLn . reverseWords)
And here is a recursive version akin to what you wanted to do in your version
reverseLines2 :: [String] -> IO ()
reverseLines2 [] = return ()
reverseLines2 (x:xs) = do
putStrLn (reverseWords x)
reverseLines2 xs
I've also fixed your version with minimal changes, but bear in mind that this is not really the Haskell way to do things. Go with one of the options I provided above.
main = do
content <- readFile "test.txt"
let linesList = lines content
reverseLines linesList
reverseWords :: String -> String
reverseWords = unwords . map reverse . words
reverseLines :: [String] -> IO ()
reverseLines inputList = do
if null inputList
then return ()
else do
let line = head inputList
if null line
then return ()
else do
putStrLn $ reverseWords line
reverseLines $ tail inputList

Resources