2011-04-19 67 views
2

用戶可以給id,width,height和description矩形,然後將其寫入文件。現在我想從文件加載這個內容到我的程序,但我有錯誤:Haskell程序中輸入錯誤

無法匹配預期類型[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 } 
+0

爲什麼是錯誤的代碼仍然在後? – Arjan 2011-04-19 17:24:00

+0

大概是這樣,問題和答案仍然有意義。 – 2011-04-20 16:27:24

回答

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單子,因爲那些東西都來自「世界」(文件系統),並舉例來說,如果你的程序執行過程中更改的文件,它可能會返回一個不同的值。

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

一個不錯的在線/ offile閱讀:http://learnyouahaskell.com/

也是一個不錯的在線/ offile閱讀:http://book.realworldhaskell.org/

+0

迄今爲止,就我從問題中可以看出,OP已經知道IO的概念。也許他只是忘記了那個單一的簽名。 – fuz 2011-04-19 16:37:06

+0

ninjagecko unfortunatelly您的代碼不適合我。我已經改變了我的代碼,現在它工作(不幸的是,我不知道我怎麼可以在評論中寫代碼 - 爲什麼所有代碼​​都在一行?): 'main = do db < - loadFile「db.txt」 MAINMENU分貝 MAINMENU RS =做 putStrLn 「選擇選項:」 ñ< - 的 「1」 函數getline 情況下,n - >做menuRectangles RS; mainMenu rs 「2」 - > putStrLn「bye,bye」 否則 - > put putStrLn「Bad option」; mainMenu rs' – mrquestion 2011-04-19 16:42:18

+0

我假設你知道我添加的** ** DB < - LOADFILE「db.txt」**'由於格式化和大小寫而不是有效的Haskell代碼;我不能說不幸,因爲我無法讀取的方式stackoverflow格式化您的代碼,並且'mainMenu'已被添加到很多地方,這是以前沒有的事實。很高興你能夠解決這個問題,儘管知道必要的微小更改會很好。 =) – ninjagecko 2011-04-19 16:53:32