Haskell:为什么说我的函数类型是关闭的?

时间:2010-04-06 23:19:43

标签: haskell functional-programming

我编写了一个小Haskell程序来查找三角形的区域,主要是为了练习自定义类型,但它在编译时不断抛出以下错误:

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: ";
                           .... }

我不确定'b'来自哪里,所以我在这里不知所措。为什么会抛出此错误,我该怎么做才能修复它?这是我的代码:

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))

感谢。 :)

2 个答案:

答案 0 :(得分:11)

getTriangle函数使用IO,因此您必须将其放在函数签名中。

getTriangle :: IO Triangle

此外,最后一行应该有return,因为它在IO函数中返回一个纯值。

return (Triangle base height)

以下是一些额外提示:Haskell可以确定baseheightDouble,因为您将它们传递给Triangle,因此您不需要以这种方式明确地声明它们。您可以使用liftM模块中的Control.Monad来阅读输入并一步转换为Double

import Control.Monad
getTriangle :: IO Triangle
getTriangle = do
    putStr "Base: "
    base <- liftM read getLine
    putStr "Height: "
    height <- liftM read getLine
    return (Triangle base height)

main函数似乎也将纯值与IO混合。由于getTriangle是IO,因此无法将其直接传递给calcTriangle。这是经过修改的main

main = do tri <- getTriangle
          putStrLn ("Area = " ++ show (calcTriangle tri))

作为脚注,三角形的区域为base * height / 2,而不是base * height

最后,一个更高级的Haskell程序员可能会根据getTriangle来编写liftM2,但这只是一种风格问题。我就是这样写的:

prompt str = putStr (str ++ ": ") >> liftM read getLine
getTriangle = liftM2 Triangle (prompt "Base") (prompt "Height")

答案 1 :(得分:3)

请注意,您可以删除getTriangle :: Triangle并通过运行:t getTriangle来表示拥抱/ ghci提示,它会告诉您它认为类型应该是什么。