Haskell 程序中的类型错误

发布于 2024-11-02 10:42:48 字数 2833 浏览 4 评论 0原文

用户可以给出 id、宽度、高度和描述矩形,然后我将其写入文件。现在我想将此内容从文件加载到我的程序中,但出现错误:

无法将预期类型 [矩形类型] 与推断类型 IO [矩形类型] 匹配。在 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 }

User can give id, width, height and description rectangle and then I write it to a file. Now I would like to load this content from the file to my program but I have error:

Couldn't match expected type [RectangleType] against inferred type IO [Rectangletype]. In the first argument of menuRectangles namely db. In the expression menuRectangles db. In a do expression menuRectangles db.

What is going on ? This is content of my file:
[Rectangle 2 5 6 "abcabc",Rectangle 1 2 4 "abcabc"]

This is code:

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 }

EDIT:
correct code:

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 }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

最后的乘客 2024-11-09 10:42:48

Haskell中有一个概念叫做纯代码。纯代码不具有以下任何内容:用户输入值、系统调用、伪随机数生成、对非纯代码的调用等。

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

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

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

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

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

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

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


为了使这个答案更明确: 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/

In Haskell there exists a concept called pure code. Pure code does not have any of the following: user-input values, system calls, pseudorandom number generation, calls to non-pure code, etc.

Pure functions are guaranteed to always always always have the same behavior based on the lexical content of your program (e.g. they can return different values, but the reason they return different values cannot depend on "the world").

This is a very powerful policy in functional languages, and allows very powerful code. For example, you know that calling a function won't change some unrelated global variable or the state of some other data structure. I often apply this policy to python code.

The way Haskell enforces the purity-impurity thing is with the IO monad.

Any of things that "the world" touches are wrapped up in the IO monad, which represented that the values have been "tainted". If anything touches these "tainted" values, the values they return must also be tainted.

You will need to run your pure code within the IO monad if you want it to have access to those values. Once within the IO monad, you can "unwrap" the value you've read and pass it into your pure code, then your pure code returns value, then you can print your value. Everything works as expected, but you have to do it in the IO monad.

Note that it is good form to ensure that most of your code is written in a pure, functional form outide of the IO monad. e.g. a pure doStuffWithRectangles function, that is then called from within the IO monad.

The beautiful thing about it is that your pure code doesn't need to know the Rectangle value has been tainted by being of type IO Rectangle. As long as you work in the IO monad, your pure code will think it is just a normal Rectangle.


And just to make this answer more explicit: readFile returns things wrapped in the IO monad, because those things come from "the world" (the filesystem) and for example if you changed the file during program execution, it might return a different value.

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

More information: http://www.haskell.org/tutorial/io.html

A good online/offile read: http://learnyouahaskell.com/

Also a good online/offile read: http://book.realworldhaskell.org/

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文