4 Replies - 3332 Views - Last Post: 06 April 2011 - 09:58 AM

#1 pmcmahon  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 26
  • Joined: 14-January 11

Haskell Output (Int/Double)

Posted 05 April 2011 - 11:07 AM

Hi

I'm writing a simple calculator program. I've got a function which parses the input string and returns a double. What I want is to check to check if the value is an integer, and if so print it out in the form e.g. '5' as opposed to '5.0'.

So, to determine if the value is an integer:
if ((value - fromIntegral (floor value)) == 0)


I brought this together with my IO function:

-- checks a value to see if it's an integer
out_type :: Double -> Char
out_type out =   if (out - fromIntegral(floor calc) > 0) then 'd'
                  else 'i'

-- handles input/output
main = do
  putStrLn "Enter calculation in reverse polish notation."
  calculation <- getLine
  if (out_type (calc calculation) == 'd') then print (calc calculation)
    else printf("%.0f" (calc calculation))

(with Text.printf imported)
but this doesn't compile. I don't think this is the most sensible way to do things either.

Does anyone have any suggestions?

Thanks in advance.

This post has been edited by pmcmahon: 05 April 2011 - 11:08 AM


Is This A Good Question/Topic? 0
  • +

Replies To: Haskell Output (Int/Double)

#2 Raynes  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 614
  • View blog
  • Posts: 2,815
  • Joined: 05-January 09

Re: Haskell Output (Int/Double)

Posted 05 April 2011 - 11:13 AM

Could you tell me what error you're getting? I can't compile this or even try it out because I don't have your calc functions and such.
Was This Post Helpful? 1
  • +
  • -

#3 pmcmahon  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 26
  • Joined: 14-January 11

Re: Haskell Output (Int/Double)

Posted 05 April 2011 - 11:16 AM

   Couldn't match expected type `t -> String'
           against inferred type `[Char]'
    In the first argument of `printf', namely
        `("%.0f" (calc calculation))'
    In the expression: printf ("%.0f" (calc calculation))
    In the expression:
        if (out_type (calc calculation) == 'd') then
            print (calc calculation)
        else
            printf ("%.0f" (calc calculation))

was the error, I've attached my complete code.

Attached File(s)


This post has been edited by pmcmahon: 05 April 2011 - 11:17 AM

Was This Post Helpful? 0
  • +
  • -

#4 Raynes  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 614
  • View blog
  • Posts: 2,815
  • Joined: 05-January 09

Re: Haskell Output (Int/Double)

Posted 06 April 2011 - 08:51 AM

Sorry for the delayed reply. I got busy yesterday. The fixes were simple. Here is the amended code:

import Char
import Text.Printf

-- number data type
data Number = Number Double
  deriving (Show, Eq, Ord, Read)

-- operation data type
data Opp =
  Add Number Number |
  Mul Number Number |
  Div Number Number |
  Sin Number |
  Cos Number |
  Tan Number
    deriving (Show, Eq, Ord, Read)

-- function evaluates expression, returns a value
evaluator :: Opp -> Double
evaluator (Add (Number x) (Number y)) = x + y
evaluator (Mul (Number x) (Number y)) = x * y
evaluator (Div (Number x) (Number y)) = x / y
evaluator (Sin (Number x)) = sin(x)
evaluator (Cos (Number x)) = cos(x)
evaluator (Tan (Number x)) = tan(x)

-- pops a value from the stack, returns the stack
pop :: [a] -> [a]
pop [] = error "empty"
pop (top:rest) = rest

-- pushes a value onto the stack, returns the stack
push :: [a] -> a -> [a]
push stack value = ([value]++stack)

-- parses a string, extracts the first number, returns it as a double
digitparser :: String -> String -> Double
digitparser (no:rest) num =
  if (isDigit no || no == '.') then digitparser rest (num ++ [no])
    else read num :: Double

-- discards all numberical values/ .s at the start of a string
moveon :: String -> String
moveon [] = []
moveon (first:rest) =
  if (isDigit first || first == '.' || isAlpha first) then moveon rest 
  else ([first] ++ rest)

-- function performs the operation indicated by an input char on the stack  
do_opp :: Char -> [Double] -> Double
do_opp c [] = error "empty"
do_opp op stack =
  if (op == '+') then evaluator (Add (Number (head stack))
    (Number (head (tail stack))))
  else if (op == '*') then evaluator (Mul (Number (head stack))
    (Number (head (tail stack))))
  else if (op == '/') then evaluator (Div (Number (head (tail stack)))
    (Number (head stack)))
  else if (op == '-') then evaluator (Add (Number ((-1)*(head stack)))
    (Number (head (tail stack))))
  else if (op == 's') then evaluator (Sin (Number (head stack)))
  else if (op == 'c') then evaluator (Cos (Number (head stack)))
  else if (op == 't') then evaluator (Tan (Number (head stack)))
  else error "unknown operation"

-- removes the top two values from the stack, replaces them with the result of
-- the operation
stackupdate :: Char -> [Double] -> [Double]
stackupdate op stack = 
  let popped = pop (pop stack) in
  let new = do_opp op stack in
    (push popped new)

-- function checks a string for 'sin' 'cos' or 'tan' 
func_parser :: String -> Char
func_parser [] = error "no input"
func_parser input =
  if ( (head input == 's' || head input == 'S') && (head (pop input) == 'i') &&
    (head (pop (pop input)) == 'n')) then 's'
  else if ( (head input == 'c'|| head input == 'C') && (head (pop input) == 'o')
    && (head (pop (pop input)) == 's')) then 'c'
  else if ( (head input == 't'|| head input == 'T') && (head (pop input) == 'a')
    && (head (pop (pop input)) == 'n')) then 't'
  else error "unknown function"

-- parses the input string and returns a value
parser :: String -> [Double] -> Double
parser [] []= error "no input"
parser [] stack = head stack
parser input stack =
  let no = head input in
  let rest = tail input in
  if (isDigit no) then parser (moveon input) (push stack (digitparser input []))
  else if (no == ' ') then parser rest stack
  else if (no == '+' || no == '*' || no == '/' || no == '-') 
    then parser rest (stackupdate no stack)
  else if (no == 's' || no == 'c' || no == 't' || 
           no == 'S' || no == 'C' || no == 'T')
    then parser (moveon input) (stackupdate (func_parser input) stack)
  else error "not accounted for"

-- calls the parser function with an empty stack
calc :: String -> Double
calc [] = error "no input"
calc input = parser input []

-- checks a value to see if it's an integer
out_type :: Double -> Char
out_type out =   if (out - fromIntegral (floor out) > 0) then 'd'
                  else 'i'

-- handles input/output
main = do
  putStrLn "Enter calculation in reverse polish notation."
  calculation <- getLine
  if (out_type (calc calculation) == 'd') then print (calc calculation)
    else printf "%.0f" (calc calculation)



You did two things wrong. First of all, you wrapped printf's arguments in parentheses. This is what was causing your error. The arguments need to be passed individually. Also, in your out_type function, you were calling floor calc, so that had to be changed to floor out.

It appears to work now.

As a side note, here are some formatting tips: name functions with camel case. out_type becomes outType. This is the standard Haskell naming scheme. Also, put a space between a function name and it's arguments, even if the argument is wrapped in parentheses. Haskell isn't C, so it looks weird. Finally, if an if/then/else expression isn't short enough to fit on a single line, put a newline before the then and the else.

digitparser :: String -> String -> Double
digitparser (no:rest) num =
  if (isDigit no || no == '.') 
  then digitparser rest (num ++ [no])
  else read num :: Double



Don't make really long if else if else if else if chains. There is almost always a better way. Use guards, pattern matching, case, anything but chains. Your chains here are so long that you're not even indenting properly so that it all stays on the screen.

That's about it. Have fun!
Was This Post Helpful? 1
  • +
  • -

#5 pmcmahon  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 26
  • Joined: 14-January 11

Re: Haskell Output (Int/Double)

Posted 06 April 2011 - 09:58 AM

Thanks! Works great now. I see what you mean about the massive chains. I'm still relatively new to Haskell and I suppose if/else is a familiar construct so I end up using it a bit too much.

Thanks for the brilliant help :-)
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1