I'm following an introductory course on functional programming, where we use Haskell. Part of an excercise is to write a parser for the input string.
However I can't 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 originates from this line:
readTrack str = parseTrack (lines str) where
parseTrack (start : finish : track) = (readLines track, readPoint start, readLine finish)
What I expected to happen is that the input string got split into a list of lines, which get passed to parseTrack. parseTrack would then use pattern matching to name the top two strings(lines) from the list and the rest.
However what I believe is happening is that finish is the top element from the list, and start gets assigned the top char from that string.
I would really like to know how to solve this problem and what is actually happening.
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)
Your variable track
was actually a list of single lines, not a string with '\n'
s in it. Since you've already split it into lines
, you can just map readLine
over it, giving:
readTrack str = parseTrack (lines str) where
parseTrack (start:finish:tracks)
= (map readLine tracks, readPoint start, readLine finish)
Here tracks :: [String]
, which is why you can map
readLine
on them all - you don't need to use readLines
to split it into lines first. (You can tell it's a list because it's the final thing to the right hand side of a :
.)
You say
However what I believe is happening is that finish is the top element from the list, and start gets assigned the top char from that string.
Well what was happening was: because you asked for readLines track
as the first output, Haskell started there, and since you declared
readLines :: String -> [Line]
that meant that track
had to be a String - that's the only thing readLines can deal with.
First, you need to remember that :
has an element on its left and a list on its right, so in
3:4:stuff
stuff
has to be [Integer]
because it's on the right of some Integer elements. Similarly,
c:"a string"
means c has to be a Char because String = [Char].
In your code, we've worked out that track
is a String, so that means that when you write
(start : finish : track)
both start and finish have to be elements you can put at the front of a String, so both start and finish have to be Char.
Haskell then looks at your code readPoint start
, but because it's worked out that start
has type Char, but
readPoint :: String -> Point
it complains that Char and String don't match.
I think you made the mistake because you forgot that readLines takes a single string, but it felt (from the name) like it should happily take a list of strings. Your parseLines looks like it does a similar thing, but it takes a list of strings, so copes, whereas readLines takes a single string with newline characters, so can't cope with a list.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With