-1

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?

Daniel Wagner
  • 145,880
  • 9
  • 220
  • 380
JMV12
  • 965
  • 1
  • 20
  • 52
  • 1
    I've removed your reimplementation of the `Prelude`, as it didn't seem relevant to your question. If you think it is relevant, feel free to revert the edit and add a short explanation of why we should pay special attention to your version of the standard functions. – Daniel Wagner Apr 05 '16 at 22:25
  • 2
    You can loop an IO action over a list with `mapM` (probably `mapM_` is more useful to you here). If `cs` are the coefficients of the polynomial and `x` is the x-value, then `sum $ zipWith (*) (reverse cs) $ iterate (*x) 1` is the value of polynomial at x. – user2407038 Apr 05 '16 at 22:58

1 Answers1

4

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 prompts


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
Random Dev
  • 51,810
  • 9
  • 92
  • 119