I am currently working on this Haskell problem and I seem to be stuck.
Write a function, evalpoly, that will ask a user for the degree of a single variable polynomial, then read in the coefficients for the polynomial (from highest power to lowest), then for a value, and will output the value of the polynomial evaluated at that value. As an example run:
> evalpoly
What is the degree of the polynomial: 3
What is the x^3 coefficient: 1.0
What is the x^2 coefficient: - 2.0
What is the x^1 coefficient: 0
What is the x^0 coefficient: 10.0
What value do you want to evaluate at: -1.0
The value of the polynomial is 7.0
As of now, I have this:
evalpoly :: IO ()
evalpoly = putStr "What is the degree of the polynomial: " >>
getLine >>= \xs ->
putStr "What is the x^" >>
putStr (show xs) >>
putStr " coefficient: " >>
putStrLn ""
How would I go about adding the loop and calculations?
Warning:
I spoil this completely so feel free to stop at any point and try to go on yourself
Instead of pushing it all into this single function I will instead break this down into smaller tasks/functions.
So let's start with this.
1. Input
On obvious part is to ask for an value - and if we are on it we can make sure that the user input is any good (I am using Text.Read.readMaybe
for this:
query :: Read a => String -> IO a
query prompt = do
putStr $ prompt ++ ": "
val <- readMaybe <$> getLine
case val of
Nothing -> do
putStrLn "Sorry that's a wrong value - please reenter"
query prompt
Just v -> return v
please note that I appended the ": "
part already so you don't have to do this for your prompt
s
having this all the questions to your user become almost trivial:
queryDegree :: IO Int
queryDegree = query "What is the degree of the polynomial"
queryCoef :: Int -> IO (Int, Double)
queryCoef i = do
c <- query prompt
return (i,c)
where prompt = "What is the x^" ++ show i ++ " coefficient"
queryPoint :: IO Double
queryPoint = query "What value do you want to evaluate at"
please note that I provide the powers together with the coefficients - this make the calculation a bit easier but is not strictly necessary here I guess (you could argue that this is more than the function should do at this point and later use zip
to get the powers too)
Asking all the inputs is now really easy once you've seen mapM
and what it can do - it's the point where you usually would want to write a loop:
queryPoly :: IO [(Int, Double)]
queryPoly = do
n <- queryDegree
mapM queryCoef [n,n-1..0]
2. Evaluation
Do evaluate this I just need to evaluate each term at the given point (that is each power, coefficient pair in the list) - which you can do using map
- after we just need to sum this all up (sum
can do this):
evaluate :: Double -> [(Int, Double)] -> Double
evaluate x = sum . map (\ (i,c) -> c*x^i)
3. Output
Is rather boring:
presentResult :: Double -> IO ()
presentResult v = putStrLn $ "The vaule of the polynomial is " ++ show v
4. Getting it all together
I just have to ask for the inputs, evaluate the value and then present it:
evalpoly :: IO ()
evalpoly = do
p <- queryPoly
x <- queryPoint
presentResult $ evaluate x p
5. Test-Run
Here is an example run
What is the degree of the polynomial: 3
What is the x^3 coefficient: 1.0
What is the x^2 coefficient: -2.0
What is the x^1 coefficient: Hallo
Sorry that's a wrong value - please reenter
What is the x^1 coefficient: 0
What is the x^0 coefficient: 10.0
What value do you want to evaluate at: -1.0
The vaule of the polynomial is 7.0
complete Code
Note that I like to enter the no-buffering because I run into trouble on Windows occasionally if I don't have it - you probably can live without
module Main where
import Control.Monad (mapM)
import Text.Read (readMaybe)
import System.IO (BufferMode(..), stdout, hSetBuffering)
query :: Read a => String -> IO a
query prompt = do
putStr $ prompt ++ ": "
val <- readMaybe <$> getLine
case val of
Nothing -> do
putStrLn "Sorry that's a wrong value - please reenter"
query prompt
Just v -> return v
queryDegree :: IO Int
queryDegree = query "What is the degree of the polynomial"
queryCoef :: Int -> IO (Int, Double)
queryCoef i = do
c <- query prompt
return (fromIntegral i,c)
where prompt = "What is the x^" ++ show i ++ " coefficient"
queryPoint :: IO Double
queryPoint = query "What value do you want to evaluate at"
queryPoly :: IO [(Int, Double)]
queryPoly = do
n <- queryDegree
mapM queryCoef [n,n-1..0]
evaluate :: Double -> [(Int, Double)] -> Double
evaluate x = sum . map (\ (i,c) -> c*x^i)
presentResult :: Double -> IO ()
presentResult v = putStrLn $ "The vaule of the polynomial is " ++ show v
evalpoly :: IO ()
evalpoly = do
p <- queryPoly
x <- queryPoint
presentResult $ evaluate x p