[英]Pattern matching from a [String] in Haskell
我正在學習函數式編程的入門課程,我們使用Haskell。 練習的一部分是為輸入字符串編寫解析器。
但是我無法解決以下錯誤,或者得到實際發生的情況。
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從該字符串分配了頂部char。
我真的很想知道如何解決這個問題以及實際發生的事情。
非常感謝!
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)
您的可變track
實際上是單行列表,而不是包含'\\n'
的字符串。 既然你已經把它分成了幾lines
,你就可以在它上面map readLine
,給出:
readTrack str = parseTrack (lines str) where
parseTrack (start:finish:tracks)
= (map readLine tracks, readPoint start, readLine finish)
這里tracks :: [String]
,這就是為什么你可以在它們上面map
readLine
原因 - 你不需要先使用readLines
將它分成行。 (你可以告訴它是一個列表,因為它是最右邊的一個:
。)
你說
然而,我認為正在發生的是,finish是列表中的頂級元素,並且start從該字符串分配了頂部char。
那么發生的事情是:因為你要求readLines track
作為第一個輸出,Haskell從那里開始,並且因為你聲明了
readLines :: String -> [Line]
這意味着該track
必須是一個字符串 - 這是readLines可以處理的唯一內容。
首先,你需要記住:
左邊有一個元素,右邊有一個列表,所以在
3:4:stuff
stuff
必須是[Integer]
因為它位於某些Integer元素的右側。 同樣的,
c:"a string"
意味着c必須是Char,因為String = [Char]。
在你的代碼中,我們已經計算出track
是一個String,這意味着你寫的時候
(start : finish : track)
開始和結束都必須是你可以放在String前面的元素,所以開始和結束都必須是Char。
然后Haskell查看你的代碼readPoint start
,但是因為它確定start
類型為Char,但是
readPoint :: String -> Point
它抱怨Char和String不匹配。
我認為你犯了錯誤,因為你忘了readLines只需要一個字符串,但它感覺(從名字中)就像它應該樂意接受一個字符串列表。 你的parseLines看起來像它做了類似的事情,但它需要一個字符串列表,所以cope,而readLines采用帶換行符的單個字符串,因此無法處理列表。
UPD 。 哦,對不起,我沒有得到那個track
意味着多個軌道,並且必須是[String]
類型。 所以AndrewC的答案更合適。
因為在haskell中,模式(x:xs)
意味着如果x
具有類型a
那么xs
必須是[a]
類型, parseTrack
中的模式意味着類型為smth (a : a : [a])
。
編譯器想要評估類型a
,首先它在右邊看到的是readLines track
。 Func readLines
類型為String -> [Line]
因此編譯器的track
為String
,這意味着[a]
的類型為String
。 另外在haskell中, String
是[Char]
所以a
是Char
。
但是你需要a
String
。 所以你只需要取前三個字符串並拋出[String]
的其余尾部。 在類型中,它意味着smth (String : String : String : [String])
。 為此,您可以將parseTrack
匹配模式重寫為:
parseTrack (start : finish : track : _)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.