I wrote a little Haskell program to find the area of a triangle, primarily to practice custom types, but it keeps throwing the follow开发者_如何转开发ing error on compile:
areafinder.hs:7:4:
Couldn't match expected type `Triangle' against inferred type `m b'
In a stmt of a 'do' expression: putStr "Base: "
In the expression:
do { putStr "Base: ";
baseStr <- getLine;
putStr "Height: ";
heightStr <- getLine;
.... }
In the definition of `getTriangle':
getTriangle = do { putStr "Base: ";
baseStr <- getLine;
putStr "Height: ";
.... }
I'm not sure where 'm b' comes from, so I'm at a loss here. Why is it throwing this error, and what can I do to fix it? Here is my code:
module Main where
data Triangle = Triangle Double Double -- base, height
getTriangle :: Triangle
getTriangle = do
putStr "Base: "
baseStr <- getLine
putStr "Height: "
heightStr <- getLine
let base = read baseStr :: Double
let height = read heightStr :: Double
Triangle base height
calcTriangle :: Triangle -> Double
calcTriangle (Triangle base height) = base * height
main = putStrLn ("Area = " ++ show (calcTriangle getTriangle))
Thanks. :)
The getTriangle
function uses IO, so you have to put that in the function signature.
getTriangle :: IO Triangle
Also, the last line should have return
, since it's returning a pure value inside an IO function.
return (Triangle base height)
Here are a couple extra tips: Haskell can figure out that base
and height
are Double
, because you pass them to Triangle
, so you don't need to explicitly declare them that way. You can use liftM
from the Control.Monad
module to read the input and convert to Double
in one step.
import Control.Monad
getTriangle :: IO Triangle
getTriangle = do
putStr "Base: "
base <- liftM read getLine
putStr "Height: "
height <- liftM read getLine
return (Triangle base height)
The main
function also appears to mix pure values with IO. Since getTriangle is IO, you can't pass it directly to calcTriangle. Here is a modified main
:
main = do tri <- getTriangle
putStrLn ("Area = " ++ show (calcTriangle tri))
As a footnote, the area of a triangle is base * height / 2
, not base * height
.
Finally, a more advanced Haskell programmer would probably write getTriangle
in terms of liftM2
, but this is just a matter of style. Here is how I would write it:
prompt str = putStr (str ++ ": ") >> liftM read getLine
getTriangle = liftM2 Triangle (prompt "Base") (prompt "Height")
Note that you can drop getTriangle :: Triangle
and by running :t getTriangle
that the hugs/ghci prompt it will tell you what it thinks the types should be.
精彩评论