簡體   English   中英

將文件讀入類型 - Haskell

[英]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數據列表?

這是家庭作業嗎?

您可能會發現這些函數很有用:

請記住, 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM