[英]Reading file into types - Haskell
現在我有兩種類型:
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 = [Film] 的文件中?
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 操作,該操作在執行時輸出該字符串。 這或多或少是您期望print
的工作方式:
Prelude> print 3 3 Prelude> print "hi" "hi"
我們知道我們想從文件中print
Film
數據,但是,雖然很好,但 ghc 無法讀取我們的想法。 但是在添加類型提示后
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"
)和副作用(例如在提示您輸入 Stack Overflow 用戶名后從鍵盤讀取輸入)之間的區別。
所以現在我們知道我們可以將readFilms
草圖為
readFilms :: FilePath -> IO Film
readFilms = undefined
和代碼編譯! (但我們還不能運行它。)
為了挖掘另一層,假設單個電影的名稱是ratings.dat
唯一的數據,並在其他地方放置占位符以使類型檢查器滿意。
readFilms :: FilePath -> IO Film
readFilms path = do
alldata <- readFile path
return (alldata, "", 0, [])
這個版本會編譯,你甚至可以通過在 ghci 提示符下輸入main
來運行它。
在dave4420 的回答中提供了有關要使用的其他功能的重要提示。 把上面的方法想象成一個拼圖,其中各個部分都是功能。 為了使您的程序正確,所有類型必須組合在一起。 如上所述,您可以通過采取一些小步驟來朝着最終工作程序取得進展,如果您的草圖有錯誤,類型檢查器會通知您。
需要弄清楚的事情:
String
)轉換為Int
以配合您對Film
的定義?readFilms
累積並返回一個Film
數據列表?這是家庭作業嗎?
您可能會發現這些函數很有用:
readFile :: FilePath -> IO String
lines :: String -> [String]
break :: (a -> Bool) -> [a] -> ([a], [a])
dropWhile :: (a -> Bool) -> [a] -> [a]
null :: [a] -> Bool
read :: Read a => String -> a
請記住, String
與[Char]
相同。
一些線索:
dropWhile null
將刪除列表開頭的空行break null
將一個列表拆分為非空行的前導運行,以及列表的其余部分 Haskell 有一個很好的方法來使用類型來找到正確的函數。 例如:在 Gregs 的回答中,他希望您弄清楚(除其他外)如何將電影的年份從 String 轉換為 Int。 嗯,你需要一個函數。 該函數的類型應該是什么? 它接受一個 String 並返回一個 Int,所以類型應該是String -> Int
。 完成后,轉到Hoogle並輸入該類型。 這將為您提供具有相似類型的函數列表。 您需要的函數實際上有一個稍微不同的類型 - Read a => String -> a
- 所以它在列表中有點低,但是猜測一個類型然后掃描結果列表通常是一個非常有用的策略。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.