2012-04-16 31 views
-1

現在我有兩種類型:閱讀文件分爲不同的類型 - 哈斯克爾

type Rating = (String, Int) 

type Film = (String, String, Int, [Rating]) 

我有了它這個數據的文件:

"Blade Runner" 
"Ridley Scott" 
1982 
("Amy",5), ("Bill",8), ("Ian",7), ("Kevin",9), ("Emma",4), ("Sam",7), ("Megan",4) 

"The Fly" 
"David Cronenberg" 
1986 
("Megan",4), ("Fred",7), ("Chris",5), ("Ian",0), ("Amy",6) 

我怎麼能看穿然後文件存儲所有的條目到像FilmDatabase = [電影]?

+0

只需簡單的事情,如:displayFile :: IO() displayFile =做 \t \t \t \t putStrLn 「輸入文件名:」 \t \t \t \t名< - 函數getline \t \t \t \t內容< - READFILE名 \t \t \t putStrLn contents – JamieB 2012-04-16 14:05:15

+0

那麼你有哪些麻煩? – dave4420 2012-04-16 14:09:43

+0

我不明白如何過濾行並將它們添加到正確的類型,如每個條目的第一行應該是一個字符串,並應添加到電影的標題(標題等等)...這類東西在C#中很簡單,但我在Haskell中發現它非常困難。 – JamieB 2012-04-16 14:18:47

回答

7

Haskell提供了一種繪製您的方法的獨特方法。你知道什麼

module Main where 

type Rating = (String, Int) 
type Film = (String, String, Int, [Rating]) 

main :: IO() 
main = do 
    films <- readFilms "ratings.dat" 
    print films 

嘗試這個程序裝入ghci中會產生

films.hs:8:12: Not in scope: `readFilms'

它需要知道什麼是readFilms,所以加足夠的代碼,以保持運動開始。

readFilms = undefined 

這是應該做的相關Film數據進行處理的功能。刷新驗證碼(與:reload命令或:r的簡稱)來獲得

films.hs:9:3: 
    Ambiguous type variable `a0' in the constraint: 
     (Show a0) arising from the use of `print' 
    ...

類型的print

Prelude> :t print 
print :: Show a => a -> IO()

換句話說,print接受一個論點,即非正式的,知道如何顯示自己(即將其內容轉換爲字符串)並創建一個I/O操作,該操作在執行時輸出該字符串。它’ S比或多或少你如何期望print工作:

Prelude> print 3 
3 
Prelude> print "hi" 
"hi"

我們知道,我們要print從文件中Film數據,但是,雖然好,可GHC ’ T上讀我們的腦海中。但添加一個類型提示後

readFilms :: FilePath -> Film 
readFilms = undefined 

我們得到一個新的錯誤。

films.hs:8:12: 
    Couldn't match expected type `IO t0' 
       with actual type `(String, String, Int, [Rating])' 
    Expected type: IO t0 
     Actual type: Film 
    In the return type of a call of `readFilms' 
    In a stmt of a 'do' expression: films <- readFilms "ratings.dat"

該錯誤告訴您編譯器對您的故事感到困惑。你說readFilms應該給它一個Film,但是你把它叫做main的方式,計算機應該先執行一些I/O,然後然後給回Film數據。

在Haskell,這是一個純粹的之間的區別,說"JamieB"和副作用,說提示您輸入您的堆棧溢出的用戶名後閱讀從鍵盤輸入。

所以,現在我們知道我們可以勾畫readFilms作爲

readFilms :: FilePath -> IO Film 
readFilms = undefined 

和代碼編譯! (但是,我們可以’噸尚未運行它。)

向下挖掘另一層,假裝一個電影的名字是ratings.dat的唯一數據,並把佔位符其他地方保持typechecker高興。

readFilms :: FilePath -> IO Film 
readFilms path = do 
    alldata <- readFile path 
    return (alldata, "", 0, []) 

該版本編譯的,你甚至可以通過在ghci的提示符下輸入main運行它。

dave4420’s answer是關於其他功能使用的很好的提示。把上面的方法想象成一個拼圖遊戲,其中單個棋子是功能。爲了您的程序正確,所有類型必須合在一起。你可以通過採取上述小補充措施來使你的最終工作計劃取得進展,如果你的草圖中有錯誤,類型分析工具會讓你知道。

事情弄清楚:

  • 你怎麼輸入的整個BLOB轉換成各行?
  • 你如何判斷你的程序正在檢查的行是標題,導演等?
  • 如何將文件中的年份(String)轉換爲Int以配合您的定義Film
  • 你如何跳過空白或空行?
  • 您如何使readFilms累積並返回Film數據列表?
0

Haskell有一個偉大的方式來使用類型來找到正確的功能。例如:在Gregs的回答中,他希望你弄清楚(除其他外)如何將電影的年份從一個字符串轉換爲一個Int。那麼,你需要一個功能。該功能的類型應該是什麼?它接受一個字符串並返回一個Int,所以類型應該是String -> Int。完成後,請轉至Hoogle並輸入該類型。這會給你一個類似類型的函數列表。您需要的功能實際上有一個稍微不同的類型 - Read a => String -> a - 因此它在列表中略有差異,但猜測一個類型,然後掃描結果列表通常是非常有用的策略。