im new in haskell, im doing my assignment , its about banking system, i get this error when i want to register new account Program error: Prelude.read: no parse
the code is below:
createAcc :: IO()
createAcc = do
new <- readFile "db.txt" --Database named db--
let new1 = length (func new)
putStrLn " Enter your Name : " --write your name--
name <- getLine
putStrLn " Enter Balance :" --enter minimum balance to deposit--
bal <- getLine
let bal1 = read bal :: Int
store <- readFile "db.txt" --entries comes in database--
let store1 = func store
let store2 = store1 ++ [(new1+1,name,bal1)]
writeFile "db.txt" (show store2)
func :: String -> [(Int,String,Int)]
func x = read x:: [(Int,String,Int)]
There's probably nothing in db.txt, hence the read is failing. Try initializing the file with the text "[]".
Also, there's a lot of things to beware of in your approach ... lazy IO is not good for writing reliable programs. You can find out more on the web, but essentially the read may not happen until you actually access the file contents, e.g. with func. At a minimum, you should use deepseq to force the reads to happen where you expect.
Related
In the below code, I am using >> to concatenate IO actions together. But AFAIU, m1>>m2 gets de-sugared to m1>>=(\_.m2) and thus it is executing the first IO action right when it is binding. I want all printing to happen in the main, i.e. print statements should not get interleaved with the input statements ("Enter Code"). Since do doesn't allow me to return any other monad than IO like [IO ()]. How can I have the desired printing effect?
f :: [Int] -> IO ()
f inventory = do
putStrLn "Enter Code\n"
x <- getLine
let idx = nameToIndex x
putStrLn "Quantity\n"
y <- getLine
putStrLn "More?\n"
c <- getChar
let q = (read y :: Int)
let curM = if inventory !! idx >= q then (putStrLn "sdaf\n") else (putStrLn "Overflow!\n")
if c == 'Y' then curM>>(f (update inventory idx)) else curM
main = f [1, 2]
I'm not 100% sure I understand the problem, but I think it goes like this: you'd like to do some interactions with the user, storing up information about the interaction, then display all the information at once at the end of the entire interaction.
Here's a very simplified version of your code, that skips all the business logic and just keeps asking the user if they want to continue.
prompt = do
putStrLn "Continue?"
s <- getLine
case s of
"y" -> putStrLn "Okay, let's continue." >> prompt
_ -> return ()
main = prompt
I think the effect you're asking for is to delay the display of "Okay, let's continue." until the user has stopped hitting "y". That's no problem. There's lots of ways you can do this. The most flexible is to have prompt return the action it wants to be executed after it completes:
prompt = do
putStrLn "Continue?"
s <- getLine
case s of
"y" -> do
act <- prompt
return (putStrLn "Okay, let's continue." >> act)
_ -> return (return ())
main = do
act <- prompt
act
(There are combinators that can make this code more compact, as well.) But I don't like this design; it makes it difficult to introspect on the result of prompt. A more specialized but also more maintainable approach is to return some data describing the interaction, which the caller can then turn into an IO action summarizing things. In this case, a list of strings seems like a suitable description.
prompt = do
putStrLn "Continue?"
s <- getLine
case s of
"y" -> do
results <- prompt
return ("Okay, let's continue." : results)
_ -> return []
main = do
results <- prompt
mapM_ putStrLn results
Hopefully this explanation is clear enough that you can combine this idea with your more complicated business logic.
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.
I'm trying to read in multiple lines from standard input in Haskell, plus one argument, then do something with the current line and write something to the standard output.
In my case I am trying to normalize lambda expressions. The program may receive 1 or more lambda expressions to normalize and then it has to write the result (normalized form or error) to the standard output. And the program may receive an argument (the max number of reductions). Here is the main function:
main :: IO ()
main = do
params <- getArgs
fullLambda <- getLine
let lambda = convertInput fullLambda
let redNum | (length params) == 1 = read (head params)
| otherwise = 100
case (parsing lambda) of
Left errorExp -> putStrLn ("ERROR: " ++ lambda)
Right lambdaExp -> do
let normalizedLambdaExp = reduction lambdaExp redNum
if (isNormalForm normalizedLambdaExp) && (isClosed lambdaExp)
then putStrLn ("OK: " ++ show normalizedLambdaExp)
else putStrLn ("ERROR: " ++ lambda)
where
convertInput :: String -> String
convertInput ('\"':xs) = take ((length xs) - 2) xs
convertInput input = input
So this code handles one line and completes the reductions and then writes something to the standard output. How can I change this to handle multiple lines? I've read about replicateM but I can't seem to grasp it. My mind is very OO so I was thinking maybe some looping somehow, but that is surely not the preferred way.
Also, this program has to be able to run like this:
echo "(\x.x) (\x.x)" | Main 25
And will produce:
OK: (\x.x)
And if there are multiple lines, it has to produce the same kind of output for each line, in new lines.
But also has to work without the argument, and has to handle multiple lines. I spent time on google and here, but I'm not sure how the argument reading will happen. I need to read in the argument once and the line(s) once or many times. Does someone know a not too lengthy solution to this problem?
I've tried it like this, too (imperatively):
main :: IO ()
main = do
params <- getArgs
mainHelper params
main
mainHelper :: [String] -> IO ()
mainHelper params = do
fullLambda <- getLine
And so on, but then it puts this to the standard output as well:
Main: <stdin>: hGetLine: end of file
Thank you in advance!
It appears you want to:
Parse a command line option which may or may not exist.
For each line of input process it with some function.
Here is an approach using lazy IO:
import System.Environment
import Control.Monad
main = do args <- getArgs
let option = case args of
[] -> ... the default value...
(a:_) -> read a
contents <- getContents
forM_ (lines contents) $ \aline -> do
process option aline
I am assuming your processing function has type process :: Int -> String -> IO (). For instance, it could look like:
process :: Int -> String -> IO ()
process option str = do
if length str < option
then putStrLn $ "OK: " ++ str
else putStrLn $ "NOT OK: line too long"
Here's how it works:
contents <- getContents reads all of standard input into the variable contents
lines contents breaks up the input into lines
forM_ ... iterates over each line, passing the line to the process function
The trick is that getContents reads standard input lazily so that you'll get some output after each line is read.
You should be aware that there are issues with lazy IO which you may run into when your program becomes more complex. However, for this simple use case lazy IO is perfectly fine and works well.
///Edit
I have a problem with haskell. If someone can help me, that would be great.
I'm inserting records into a file using the following code:
check :: Int -> Int
check a
|a > 0 && a<=10 = a
|otherwise = error "oh. hmm.. enter a number from the given interval"
ame :: IO ()
ame = do
putStr "Enter the file name: "
name <- getLine
putStrLn "Do you want to add new records? "
question <- getLine
if question == "yes" then do
putStrLn "Enter your records:"
newRec <- getLine
appendFile name ('\n':newRec)
--new lines--
putStrLn "enter a number between 0 and 10: "
something <- getLine
return (read something:: Int)
let response = check something
putStrLn response
appendFile name ('\n':something)
putStrLn "enter something new again: "
something2 <- getLine
appendFile name ('\n':something2)
putStrLn "a"
else
putStr "b"
Now I want to extract some records from this file, using a specific criteria. For example, i want to extract and display records from even(or odd or any other criteria) rows. can I do that? if yes, how?
Also...
I want to check the user input. Let's say that I don't want him/her to enter a string instead of an integer. can I also check his/her input? do I need to create another function and call that function inside the code from above?
///Edit
thank you for answering. but how can i embed it into my previous code?
I've tried now to create a function(you can see the above code) and then call that function in my IO. but it doesn't work..
Yes, it is certainly possible to display only certain rows. If you want to base it off of the row number, the easiest way is to use zip and filter
type Record = String
onlyEven :: [Record] -> [Record]
onlyEven records =
map snd $ -- Drop the numbers and return the remaining records
filter (even . fst) $ -- Filter by where the number is even
zip [1..] -- All numbers
records -- Your records
This technique can be used in a lot of circumstances, you could even abstract it a bit to
filterByIdx :: Integral i => (i -> Bool) -> [a] -> [a]
filterByIdx condition xs = map snd $ filter (condition . fst) $ zip [1..] xs
-- Could also use 0-based of `zip [0..] xs`, up to you
onlyEven :: [a] -> [a]
onlyEven = filterByIdx even
If you want to check if an input is an Int, the easiest way is to use the Text.Read.readMaybe function:
import Text.Read (readMaybe)
promptUntilInt :: IO Int
promptUntilInt = do
putStr "Enter an integer: "
response <- getLine
case readMaybe response of
Just x -> return x
Nothing -> do
putStrLn "That wasn't an integer!"
promptUntilInt
This should give you an idea of how to use the function. Note that in some cases you'll have to specify the type signature manually as case (readMaybe response :: Maybe Int) of ..., but here it'll work fine because it can deduce the Int from promptUntilInt's type signature. If you get an error about how it couldn't figure out which instance for Read a to use, you need to manually specify the type.
You have
something <- getLine
return (read something:: Int)
let response = check something
putStrLn response
To step through what you're trying to do with these lines:
something <- getLine
getLine has the type IO String, meaning it performs an IO action and returns a String. You can extract that value in do notation as
something <- getLine
Just as you have above. Now something is a String that has whatever value was entered on that line. Next,
return (read something :: Int)
converts something to an Int, and then passes it to the function return. Remember, return is not special in Haskell, it's just a function that wraps a pure value in a monad. return 1 :: Maybe Int === Just 1, for example, or return 1 :: [Int] === [1]. It has contextual meaning, but it is no different from the function putStrLn. So that line just converts something to an Int, wraps it in the IO monad, then continues on to the next line without doing anything else:
let response = check something
This won't compile because check has the type Int -> Int, not String -> String. It doesn't make any sense to say "hello, world" > 0 && "hello, world" <= 10, how do you compare a String and an Int? Instead, you want to do
let response = check (read something)
But again, this is unsafe. Throwing an error on an invalid read or when read something is greater than 10 will crash your program completely, Haskell does errors differently than most languages. It's better to do something like
check :: Int -> Bool
check a = a > 0 && a <= 10
...
something <- getLine
case readMaybe something of
Nothing -> putStrLn "You didn't enter a number!"
Just a -> do
if check a
then putStrLn "You entered a valid number!"
else putStrLn "You didn't enter a valid number!"
putStrLn "This line executes next"
While this code is a bit more complex, it's also safe, it won't ever crash and it handles each case explicitly and appropriately. By the way, the use of error is usually considered bad, there are limited capabilities for Haskell to catch errors thrown by this function, but errors can be represented by data structures like Maybe and Either, which give us pure alternatives to unsafe and unpredictable exceptions.
Finally,
putStrLn response
If it was able to compile, then response would have the type Int, since that's what check returns. Then this line would have a type error because putStrLn, as the name might suggest, puts a string with a new line, it does not print Int values. For that, you can use print, which is defined as print x = putStrLn $ show x
Since this is somewhat more complex, I would make a smaller function to handle it and looping until a valid value is given, something like
prompt :: Read a => String -> String -> IO a
prompt msg failMsg = do
putStr msg
input <- getLine
case readMaybe input of
Nothing -> do
putStrLn failMsg
prompt
Just val -> return val
Then you can use it as
main = do
-- other stuff here
-- ...
-- ...
(anInt :: Int) <- prompt "Enter an integer: " "That wasn't an integer!"
-- use `anInt` now
if check anInt
then putStrLn $ "Your number multiplied by 10 is " ++ show (anInt * 10)
else putStrLn "The number must be between 1 and 10 inclusive"
You don't have to make it so generic, though. You could easily just hard code the messages and the return type like I did before with promptUntilInt.
I want the user to enter a list of tuples to search on it for a key like this can I say it like this
data BookInfo = Book Int String [String]
deriving(Show)
findbook :: [BookInfo] -> Int -> BookInfo
findbook vs key = (booker (vs!!(bookFinding vs key 0 (length vs))) key)
getBookInfo = do
putStrLn "Enter book id :"
k <- read
putStrLn "Enter book name : "
r <- getLine
putStrLn "Enter book subject :"
m <- getLine
let Book book = enter k r [m]
return book
main = do
putStr "Enter you first info is :"
v <- getBookInfo
let Book vs = v:[]
c <- getLine
if c == "N"
then
putStr "You done"
else
Book booke = getBookInfo
vs = booke:vs
putStr "Do you want to search ? :"
m <- getch
if m == 'y'
then
putStr " Enter your key :"
s <- readNum
let Book w = findBook vs s
putStrLn" The result is: " ++ show(w)
But it gives me an error:
The last statement in do must be m <- getch
What am I doing wrong?
It looks like you're trying to write a program to read a list of books into some sort of database, and then search the books. You start off well, with a data type that stores book info:
data BookInfo = Book Int String [String] deriving (Show)
Now let's look at your function which reads in book info from the user.
getBookInfo = do
putStrLn "Enter book id :"
k <- read
putStrLn "Enter book name : "
r <- getLine
putStrLn "Enter book subject :"
m <- getLine
let Book book = enter k r [m]
return book
I fixed up your indentation for you (here's a tip: use four spaces for indentation!) but there are other problems:
The line k <- read doesn't make any sense. The type of read is read :: Read a => String -> a but you're using it as if it was an I/O action. You need the function readLn instead.
The line let Book book = enter k r [m] doesn't make any sense. It looks like you're used to writing in a language like C or Java, where you have to specify types. You don't have to do that in Haskell! Also, the enter function is unnecessary. You can just write let book = Book k r [m] and that will work fine. In fact, you don't need the temporary variable book at all - you can create the Book and return it all in one line.
So you can write:
getBookInfo :: IO BookInfo
getBookInfo = do
putStrLn "Enter book id: "
bookid <- readLn
putStrLn "Enter book name: "
name <- getLine
putStrLn "Enter book subject: "
subject <- getLine
return (Book bookid name [subject])
which will now compile fine. Notice that I also added a type declaration (which is optional).
Your next function, main, is trying to do a bit too much. It contains all the rules for getting a list of books, and the rules for searching them. These are two separate tasks, so they should be in two separate functions. So let's write a function that gets a list of books:
getBookList :: IO [BookInfo]
getBookList = do
putStr "Any more books? "
answer <- getLine
if answer == "N"
then return []
else do
book <- getBookInfo
books <- getBookList
return (book:books)
Take a while to understand how this function works. First it asks if you have any more books to enter. If you say "N" then it returns the empty list, and you're done. Otherwise, it does something magical - first, it calls getBookInfo to get the info for a single book. Then it calls itself to get a list of books! This is an example of recursion. Finally, it adds the first book to the list of books, and returns the whole list.
You should have a go at writing the rest of the program yourself now. I may revisit this answer in a day or so to add some more detail. I'm more likely to do that if you leave a comment letting me know what you're tried, and where you get stuck. Remember:
Indent your code properly! Use four spaces. Get an editor like Sublime Text 2 that knows how to handle indentation.
Try and write small (less then 10 lines) functions and chain them together to make a complete program. This will prevent you from losing your mind when trying to debug the 400 line monstrosity you've come up with.
Check the types! You can load up ghci and type, for example, :t read to see the type of the read function.