Question

I have a custom datatype similar to:

data Token = Number Int
           | Otherthings

I want to be able to use the "Number" in one way and other things in another. So I can successfully create a case statement like:

parse x = case x of
    Number y -> y

Which then successfully takes:

let x = Number 7 in parse x

And evaluates to 7. However, when I try to change the "parse" function to be:

parse [] = []
parse (x:xs) = case x of
    Number y -> y

I get the error:

Couldn't match expected type `[a0]' with actual type `Int'
In the expression: y
In a case alternative: Number y -> y
In the expression: case x of { Number y -> y }

Why doesn't this work this way and what's the proper way to approach this problem? Thank you much!

Was it helpful?

Solution

Look at the types of the two parts of parse's definition separately.

parse :: [a] -> [b] -- both the []'s are lists of some (possibly different) type
parse [] = []

and

parse :: [Token] -> Int -- y, the function's return value, is an Int.
parse (x:xs) = case x of
    Number y -> y

and you can see that while a ~ Token works just fine, [b] ~ Int doesn't work: an Int is not a list of something. (The error message is using a0 where I'm using b.)

The way out of this is to think about what type you want parse to return, and make sure all the parts of its definition match it. I'm not sure exactly what you want parse to do, so I can't give a definite answer there.

OTHER TIPS

Your two definitions of parse have different types. parse [] returns a list, whereas parse (x:xs) returns a naked number.

You could make it work, e.g., by returning the number in a singleton list

parse [] = []
parse (x:xs) = case x of
    Number y -> [y]

or by returning a number for the empty-list case

parse [] = 0
parse (x:xs) = case x of
    Number y -> y

or in a number of other ways, depending on what you want to achieve.

The problem is that your second parse function is returning a List when passed the empty list and it is trying to return a Int when passed a non-empty List. That's what the compiler is complaining about.

When you are using a case or pattern matching is good practice to write all the possible constructors. Think about what would happens in your parse function when someone call it with [Otherthings, Number 3] for example.

You should probably use Maybe instead and match all constructors of the Data type:

parse []     = Nothing
parse (x:xs) = case x of
    Number y    -> Just y
    Otherthings -> Nothing

You already have

parse x = case x of
    Number y -> y

And you want to have parseList, it looks like:

parseList = map parse

or write it in more verbose way:

parseList [] = []
parseList (x:xs) = parse x : parseList xs

or

parseList [] = []
parseList (x:xs) = case x of
    Number y -> y : parseList xs

Maybe you forgot to parse rest elements, parsing only first one

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top