Reputation: 35
So I've been enjoying this challenging language, I am currently working on an assignment for school.
This is what it says: I need to prompt the user for a list of numbers, then display the average of the list , I am so close to figuring it out. However I get this weird parse error:
"Exception: user error (Prelude.readIO: no parse)"
Here is my code:
module Main (listM', diginums', getList, main) where
import System.IO
import Data.List
diginums' = []
listM' = [1, 2, 3]
average' = (sum diginums') / (fromIntegral (length diginums'))
getList :: IO [Double]
getList = readLn
main = do
putStrLn "Please enter a few numbers"
diginums' <- getList
putStrLn $ show average'
Terminal Prompts : Enter a few #'s
I Enter : 123
ERROR : Exception: user error (Prelude.readIO: no parse)
I know my functions are working correctly to calculate the average. Now I think my problem is that when I take in the list of numbers from the user, I don't correctly parse them to type Double
for my average function.
Upvotes: 1
Views: 1175
Reputation: 58735
There are no mutable variables in Haskell, but it looks like you are trying to initialise diginums'
as an empty list and then populate it with getList
.
Instead, maybe you want to pass the list of numbers to average'
as an argument, something like:
module Main (getList, main) where
import System.IO
import Data.List
average' ds = (sum ds) / (fromIntegral (length ds))
getList :: IO [Double]
getList = readLn
main = do
putStrLn "Please enter a few numbers"
diginums' <- getList
putStrLn $ show $ average' diginums'
Also, as Daniel said, you need to input using Haskell literal List syntax, given the way you've coded it.
Upvotes: 3
Reputation: 183888
Your type signature says that
getList :: IO [Double]
getList = readLn
reads a list of Double
s, that means it expects input of the form
[123, 456.789, 1011.12e13]
but you gave it what could be read as a single number, "123"
. Thus the read
fails, the input couldn't be parsed as a [Double]
.
If you want to parse input in a different form, not as syntactically correct Haskell values, for example as a space-separated list of numbers, you can't use readLn
, but have to write a parser for the desired format yourself. For the mentioned space-separated list of numbers, that is very easy, e.g
getList :: IO [Double]
getList = do
input <- getLine
let nums = words input
return $ map read nums
If you want to get the list in the form of numbers each on its own line, ended by an empty line, you'd use a recursion with an accumulator,
getList :: IO [Double]
getList = completeList []
completeList :: [Double] -> IO [Double]
completeList acc = do
line <- getLine
if null line
then return (reverse acc)
else completeList (read line : acc)
Parsers for more complicated or less rigid formats would be harder to write.
When the parsing is fixed, you run into the problem that you haven't yet got used to the fact that values are immutable.
diginums' = []
listM' = [1, 2, 3]
average' = (sum diginums') / (fromIntegral (length diginums'))
defines three values, the Double
value average'
is defined in terms of the empty list diginums'
, hence its value is
sum diginums' / fromIntegral (length diginums') = 0 / 0
which is a NaN
.
What you need is a function that computes the average of a list of Double
s, and apply that to the entered list in main
.
average :: [Double] -> Double
average xs = sum xs / fromIntegral (length xs)
main = do
putStrLn "Please enter a few numbers"
numbers <- getList
print $ average numbers
Upvotes: 3