2012-09-17 65 views
4

我正在學習使用Haskell的函數式編程入門課程。 練習的一部分是爲輸入字符串編寫解析器。Haskell中的[String]模式匹配

但是我無法解決以下錯誤,或得到實際發生的事情。

Parser.hs:29:71: 
Couldn't match expected type `String' with actual type `Char' 
In the first argument of `readPoint', namely `start' 
In the expression: readPoint start 
In the expression: 
    (readLines track, readPoint start, readLine finish) 

錯誤從這一行來源:

readTrack str = parseTrack (lines str) where 
    parseTrack (start : finish : track) = (readLines track, readPoint start, readLine finish) 

我希望發生的是,輸入字符串得到了拆分成線,其中獲得傳遞給parseTrack的列表。 然後,parseTrack將使用模式匹配來從列表和其他名稱中命名前兩個字符串(行)。

但是我相信發生的事情是finish是列表中的頂部元素,並且start會從該字符串中分配頂部字符。

我真的很想知道如何解決這個問題以及實際發生的事情。

非常感謝!

Parser.hs

module Parser where 

import Types 

readFloat :: String -> Float 
readFloat str = case reads str of 
    [] -> error "not a floating point number" 
    (p,_):_ -> p 

readInt :: String -> Int 
readInt str = case reads str of 
    [] -> error "not an integer" 
    (p,_):_ -> p 

readPoint :: String -> Point 
readPoint str = parsePoint (words str) where 
    parsePoint (x : y : _) = (readInt x, readInt y) 

readLine :: String -> Line 
readLine str = parseLine (words str) where 
    parseLine (x1 : y1 : x2 : y2 : _) = ((readInt x1, readInt y1), (readInt x2, readInt y2)) 

readLines :: String -> [Line] 
readLines str = parseLines (lines str) where 
    parseLines (line : rest) = readLine line : parseLines rest 

readTrack :: String -> Track 
readTrack str = parseTrack (lines str) where 
    parseTrack (start : finish : track) = (readLines track, readPoint start, readLine finish) 

Types.hs

module Types where 

type Vector2D = (Int, Int) 
type Point  = Vector2D 
type Line  = (Point, Point) 
type Velocity = Vector2D 

type CarState = (Position, Velocity) 
type Position = Vector2D 
type Trace  = [Position] 

type Track  = ([Line], Point, Line) 

回答

7

你的變量track竟是單行列表,而不是一個與'\n',它出現的字符串。既然你已經將它分成lines,你可以map readLine過它,贈送:

readTrack str = parseTrack (lines str) where 
    parseTrack (start:finish:tracks) 
        = (map readLine tracks, readPoint start, readLine finish) 

這裏tracks :: [String],這就是爲什麼你可以對他們所有mapreadLine - 你不需要使用readLines分裂它首先成行。(你可以告訴它是一個列表,因爲它是一個:的右側的最​​後一件事。)

你說

但是我認爲正在發生的是完成從列表中的頂級元素,並開始獲取該字符串中的頂部字符。

那麼發生了什麼事是:因爲你問readLines track作爲第一輸出,哈斯克爾在那裏開始了,既然你宣佈

readLines :: String -> [Line] 

這意味着track必須是一個字符串 - 這是唯一的readLines可以處理的事情。

首先,你必須記住,:在其左側的元素,並在其右側的列表,所以在

3:4:stuff 

stuff必須是[Integer],因爲它是在一些整數元素的權利。同樣,

c:"a string" 

意味着c必須是Char,因爲String = [Char]。

在代碼中,我們已經計算出track是一個字符串,這樣就意味着,當你寫

(start : finish : track) 

兩個起點和終點必須是,你可以把一個字符串的前部元件,所以開始和結束都必須是Char。

哈斯克爾然後看你的代碼readPoint start,而是因爲它的工作指出,start具有char類型,但

readPoint :: String -> Point 

它抱怨說,字符和字符串不匹配。

我想你犯了這個錯誤,因爲你忘記了readLines只接受一個字符串,但它感覺(從名字)喜歡它應該愉快地接受一個字符串列表。你的parseLines看起來像它做了類似的事情,但它需要一個字符串列表,所以copes,而readLines採用單行字符串換行符,所以不能應付列表。

+0

Wonderfull答案,解決了這個問題,並提高了我對如何評估類型的理解。 +1爲您先生! –

0

UPD。哦,對不起,我沒有得到那track意味着多軌,必須是[String]類型。所以來自AndrewC的答案更適合。

由於在Haskell模式(x:xs)意味着如果x具有類型a然後xs必須[a]類型的你在parseTrack模式是指各類不服像(a : a : [a])
編譯器要評估類型a,首先它在右側看到的是readLines track。 Func readLines的類型爲String -> [Line],因此編譯器的trackString,這意味着[a]的類型爲String。另外在haskell String[Char]所以aChar
但是,您需要a作爲String。所以你只需要先取三個字符串,然後扔掉[String]的剩餘尾部。在類型中,它意味着像(String : String : String : [String])那樣的不合適。對於它,你可以在parseTrack重寫匹配模式:

parseTrack (start : finish : track : _)