I am trying to make a main function that takes 2 Realfloat input and pass through this function
bmiTell :: (RealFloat a) => a -> a -> String
bmiTell weight height
| bmi <= 18.5 = "You're underweight"
| bmi <= 25.0 = "You're normal"
| bmi <= 30.0 = "You're overweight"
| otherwise = "You're obese"
where bmi = weight / height ^ 2
And my solution is, where I trying to get weight and height and pass it through the bmiTell funtion
main = do
putStrLn "What's your weight?"
weight <- getLine
putStrLn "What's your height?"
height <- getLine
print (bmiTell( read weight ::Float, read height ::Float))
and this is giving this error
* No instance for (Show ((Float, Float) -> String))
arising from a use of `print'
(maybe you haven't applied a function to enough arguments?)
* In a stmt of a 'do' block:
print (bmiTell (read weight :: Float, read height :: Float))
In the expression:
do putStrLn "What's your weight?"
weight <- getLine
putStrLn "What's your height?"
height <- getLine
....
In an equation for `main':
main
= do putStrLn "What's your weight?"
weight <- getLine
putStrLn "What's your height?"
....
|
14 | print (bmiTell( read weight ::Float, read height ::Float))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
getbmi.hs:14:12: error:
* No instance for (RealFloat (Float, Float))
arising from a use of `bmiTell'
* In the first argument of `print', namely
`(bmiTell (read weight :: Float, read height :: Float))'
In a stmt of a 'do' block:
print (bmiTell (read weight :: Float, read height :: Float))
In the expression:
do putStrLn "What's your weight?"
weight <- getLine
putStrLn "What's your height?"
height <- getLine
....
|
14 | print (bmiTell( read weight ::Float, read height ::Float))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
I understand that RealFloat is Double or Float. Can anyone How to get input for RealFloat and pass it through a function.
For simplicity, I will in the following discuss a monomorphic version of your function, i.e.
bmiTell :: Double -> Double -> String
(For a RealFloat
, the type Double
is usually the only sensible choice.)
Your code would actually work if you had defined
bmiTell :: (Double, Double) -> String
bmiTell(weight, height)
| ...
That would be the “normal way” to define a multi-parameter function, as most other programming languages would do it. In this case bmiTell (read weight, read height)
would work.
You can do this in Haskell, however we prefer a different style that is in many ways equivalent but offers some nice advantages, though it is often confusing for beginners: we Curry most multi-parameter functions.
It can be explained quite simply: instead of supplying both arguments at once, in a tuple, you supply first one argument, then the next. And so on. So, you have the function bmiTell
. You give it the argument w
, i.e. you write bmiTell w
. Then you also give it the argument h
, so you write (bmiTell w) h
, where the parser allows us to omit the parentheses.
The function has thus the signature bmiTell :: Double -> SOMETHING
, where SOMETHING
must be able to accept another parameter... and only then give a string. So, in fact
bmiTell :: Double -> (Double -> String)
Here too, the parsing rules were deliberately chosen so we can actually just omit the parentheses.
To use that function, you must, well – give both arguments one-by-one.
bmiTell (read weight) (reight height)
In the whole program:
main :: IO ()
main = do
putStrLn "What's your weight?"
weight <- getLine
putStrLn "What's your height?"
height <- getLine
print (bmiTell (read weight) (read height))
Actually we like to omit even more parentheses (we're not Lispers!), which can be done by using the handy no-op $
operator:
print $ bmiTell (read weight) (read height)