Pattern matching from [String] in Haskell

I am following an introductory course in functional programming, where we use Haskell. Part of the exercise is to write a parser for the input string.

However, I cannot solve the following error or get what is actually happening.

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) 

The error occurs from this line:

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

I expected the input string to be split into a list of strings that are passed to parseTrack. Then parseTrack will use pattern matching to name the top two lines (lines) from the list and the rest.

However, what I think is happening because the finish is the top item from the list, and start gets the designated top char from this line.

I would really like to know how to solve this problem and what really happens.

Thanks a lot!

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) 
+4
source share
2 answers

Your track variable was actually a list of single lines, not a line with '\n' . Since you have already divided it into lines , you can simply map readLine above it by specifying:

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

Here tracks :: [String] , so you can map readLine to all of them - you do not need to use readLines to split it into lines first. (You can tell him the list because this is the last thing on the right side : )

You speak

However, what I think is happening because the finish is the top item from the list, and start gets the designated top char from this line.

Well, what happened: because you requested readLines track as the first output, Haskell started there, and since you announced

 readLines :: String -> [Line] 

which meant that track was supposed to be String - this is the only thing readLines can read.

First, you need to remember that : has an element on the left and right on the right, so in

 3:4:stuff 

stuff must be [Integer] because it is to the right of some Integer elements. Similarly

 c:"a string" 

means c must be char because String = [Char].

In your code, we found out that track is a string, so that means when writing

 (start : finish : track) 

both the beginning and the end must be elements that you can put before the line, so the beginning and the end must be Char.

Haskell then looks at your readPoint start code, but because it has start type Char, but

 readPoint :: String -> Point 

he complains that char and String do not match.

I think you made a mistake because you forgot that readLines takes one line, but she felt (on behalf of) that she should happily take a list of lines. Your parseLines look as if it looks like a similar thing, but it takes a list of lines, so it copies, while readLines takes one line with newline characters, so it cannot handle the list.

+7
source

UPD Oh, sorry, I didn’t understand that track means multiple tracks and should be of type [String] . So the answer from AndrewC is more suitable.

Since in haskell the pattern (x:xs) means that if x is of type a , then xs should be of type [a] your pattern in parseTrack means in smth types, like (a : a : [a]) .
The compiler wants to evaluate type a , and first what it sees on the right is readLines track . Func readLines is of type String -> [Line] , so the compiler has track as String , which means that [a] is of type String . Also in haskell String is [Char] , so a is Char .
But you need a as String . So you just need to take the first three lines and throw away the remaining tail [String] . In types, this will mean smth, like (String : String : String : [String]) . To do this, you can rewrite the appropriate template in parseTrack for:

 parseTrack (start : finish : track : _) 
0
source

Source: https://habr.com/ru/post/1434705/


All Articles