在Haskell程序中键入错误

时间:2011-04-19 15:54:27

标签: haskell io monads

用户可以给出id,width,height和description矩形,然后将其写入文件。现在我想将这个内容从文件加载到我的程序,但是我有错误:

无法将预期类型[RectangleType]与推断类型IO [Rectangletype]匹配。在menuRectangles的第一个参数中,即db。在表达式menuRectangles db中。在do表达式menuRectangles db中。

发生了什么事?这是我的文件的内容: [矩形2 5 6“abcabc”,矩形1 2 4“abcabc”]

这是代码:

import IO
import Char
import System.Exit
import Maybe


data RectangleType = Rectangle Int Int Int deriving(Show, Read)


loadFile :: FilePath -> IO [RectangleType]
loadFile fname =
    catch (do fileContent <- readFile fname
              return (read fileContent)
    ) errorHandler
    where
        errorHandler e = do putStrLn ("Error file")
                            exitFailure

db = loadFile "db.txt"


main = do
    putStrLn "Choose option:"
    n <- getLine
    case n of
        "1"         -> do menuRectangles db; main
        "2"         -> putStrLn "bye, bye"
        otherwise   -> do putStrLn "Bad option"; main


menuRectangles :: [RectangleType] -> IO [RectangleType]
menuRectangles rs = do
    putStrLn "Please choose option:"
    putStrLn "1 - Add rectangle"
    putStrLn "2 - Show rectangle"
    putStrLn "3 - Quit"
    putStr "Number: "
    n <- getLine
    case n of
        "1"         ->  do { {- rs_new <- addRectangle rs; -} menuRectangles rs };
        "2"         ->  do { {- showRectangle rs; -} menuRectangles rs }
        "3"         ->  do { putStrLn "Quitting"; return rs }
        otherwise   ->  do { putStrLn "The End"; return rs }

修改: 正确的代码:

import IO
import Char
import System.Exit
import Maybe


data RectangleType = Rectangle Int Int Int deriving(Show, Read)


loadFile :: FilePath -> IO [RectangleType]
loadFile fname =
    catch (do fileContent <- readFile fname
              return (read fileContent)
    ) errorHandler
    where
        errorHandler e = do putStrLn ("Error file")
                            exitFailure


main = do
    db <- loadFile "db.txt"
    mainMenu db


mainMenu rs = do
    putStrLn "Choose option:"
    n <- getLine
    case n of
        "1"         -> do menuRectangles rs; mainMenu rs
        "2"         -> putStrLn "bye, bye"
        otherwise   -> do putStrLn "Bad option"; mainMenu rs


menuRectangles :: [RectangleType] -> IO [RectangleType]
menuRectangles rs = do
    putStrLn "Please choose option:"
    putStrLn "1 - Add rectangle"
    putStrLn "2 - Show rectangle"
    putStrLn "3 - Quit"
    putStr "Number: "
    n <- getLine
    case n of
        "1"         ->  do { {- rs_new <- addRectangle rs; -} menuRectangles rs };
        "2"         ->  do { {- showRectangle rs; -} menuRectangles rs }
        "3"         ->  do { putStrLn "Quitting"; return rs }
        otherwise   ->  do { putStrLn "The End"; return rs }

1 个答案:

答案 0 :(得分:5)

在Haskell中存在一个称为纯代码的概念。纯代码不具有以下任何一项:用户输入值,系统调用,伪随机数生成,对非纯代码的调用等。

保证纯函数始终总是基于程序的词法内容具有相同的行为(例如,它们可以返回不同的值,但它们返回不同值的原因不能取决于“世界”)。

这是功能语言中非常强大的策略,并且允许非常强大的代码。例如,您知道调用函数不会更改某些不相关的全局变量或某些其他数据结构的状态。我经常将此策略应用于python代码。

Haskell强制执行纯度杂质的方式是使用IO monad。

“世界”触及的任何事物都包含在IO monad中,这表示价值已被“污染”。如果有什么东西触及这些“受污染”的值,它们返回的值也必须受到污染。

如果您希望它能够访问这些值,则需要在IO monad中运行纯代码。一旦进入IO monad,你可以“解开”你读过的值并将其传递给纯代码,然后你的纯代码返回值,然后你可以打印你的值。一切都按预期工作,但你必须在IO monad中完成。

请注意,确保大多数代码都是以IO monad的纯函数形式编写,这是一种很好的形式。例如一个纯doStuffWithRectangles函数,然后从IO monad中调用。

关于它的美妙之处在于,您的纯代码不需要知道Rectangle值已被IO Rectangle类型所污染。只要你在IO monad中工作,你的纯代码就会认为它只是一个普通的Rectangle


只是为了使这个答案更明确:readFile返回包含在IO monad中的内容,因为这些内容来自“世界”(文件系统),例如,如果你在程序执行期间更改了文件,它可能会返回不同的值。

--db = loadFile "db.txt" REMOVED--

main = do --within the IO monad
    putStrLn "Choose option:"
    n <- getLine
    **DB <- LOADFILE "db.txt"** --db is now a pure value
    case n of
        "1"         -> do menuRectangles db; main
        "2"         -> putStrLn "bye, bye"
        otherwise   -> do putStrLn "Bad option"; main

更多信息:http://www.haskell.org/tutorial/io.html

良好的在线/离线阅读:http://learnyouahaskell.com/

也是一个很好的在线/非法阅读:http://book.realworldhaskell.org/