在Haskell程序中键入错误

mrq*_*ion 2 io monads haskell

用户可以给出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 }
Run Code Online (Sandbox Code Playgroud)

编辑:正确的代码:

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 }
Run Code Online (Sandbox Code Playgroud)

nin*_*cko 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
Run Code Online (Sandbox Code Playgroud)

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

一个很好的在线/离线阅读:http://learnyouahaskell.com/

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