簡體   English   中英

來自Haskell中[String]的模式匹配

[英]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]因此編譯器的trackString ,這意味着[a]的類型為String 另外在haskell中, String[Char]所以aChar
但是你需要a String 所以你只需要取前三個字符串並拋出[String]的其余尾部。 在類型中,它意味着smth (String : String : String : [String]) 為此,您可以將parseTrack匹配模式重寫為:

parseTrack (start : finish : track : _)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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