1

Just a quick disclaimer I have been learning Haskell for about a month and have been reading, watching and searching the web but I just cant get my head around this.

So my question is, I want to compare two strings say "p16201348" & "p16202068" and basically check that the first two numbers after the p are from the year 2016 so 16. In my first example below i'm just using the same lists to compare. When I input this into ghci then it evaluates to true as you would expect. My problem is actually writing this as a callable function.

"p16201348" !! 1 == '1' && "p16201348" !! 1 == '1' && "p16201348" !! 2 == '6' && "p16201348" !! 2 == '6'

My first attempt at writing the function is below, as I said the p is irrelevant so from what I understand I split the list into x:xs butt disregard the head which ends up being _:xs and _:ys. When I try and call this I get the ambiguous occurrence.

compare (_:xs) (_:ys) = xs !! 1 == '1' && ys !! 1 == '1' && xs !! 2 == '6' && ys !! 2 == '6'

My final function (protptype) is using a guarded equation, although im not even sue if it is possible to split a list and then evaluate certain elements within it

compare (_:xs)(_:ys)
    | xs !! 1  == '1' && ys !! 1 == '1' &&  xs !! 2  == '6' &&  ys !! 2 == '2' = "Same Year"
    | otherwise = "Different year"

Thanks in advance for any help.

3
  • Not sure why but my underscores have not shown in front of :xs, :ys etc.. Commented Feb 27, 2018 at 13:13
  • They show for me. It might just be your browser. Commented Feb 27, 2018 at 13:16
  • I guess I thought getting rid of the head it wouldn't get in the way when comparing although looking at it i suppose it doesn't matter as i'm not using the head in the comparison. I am getting an error, Ambiguous Occurrence wit that last piece of code. Commented Feb 27, 2018 at 13:23

2 Answers 2

4

We can make it more elegant, by performing the equality checks already in the pattern matching part. Furthermore your function is missing the case where for instance the digits are not equal, or when I pass an invalid string.

For instance for the year "16" case, we can use:

-- only works for the year 16
compare (_:'1':'6':_) (_:'1':'6':_) = "Same year"
compare _ _ = "Different year"

So the first line checks whether the second and third element of the lists are '1' and '6' respectively. Only in that case we return "Same year". In all other cases (the second line) we return "Different year". The last line will thus fire in case one of the strings has less than three characters, or when both strings have at least three characters, but the second and third character are not '1' and/or '6' respectively.

Now in case we want to generalize this for any year, we can use variables:

compare (_:x1:x2:_) (_:y1:y2:_) = ...
compare _ _ = "Different year"

So here x1 is the second character of the first string, x2 is the third character of the same string. y1 is the second character of the second string, and y2 is the third character of the second string.

We probably want to ensure that these are all digits, so we can check:

import Data.Char(isDigit)

compare (_:x1:x2:_) (_:y1:y2:_) | all isDigit [x1, x2, y1, y2] = ...
compare _ _ = "Different year"

So now we have guarantees that if the guard "fires" that all these characters are digits (in the 0 to 9 range). But of course we still need to determine that these have the same value.

I leave what you have to fill in for the ellipse (...) as an exercise, it is basically a generalization of the code in the question.

Sign up to request clarification or add additional context in comments.

4 Comments

Thanks a lot for your help, that makes a lot of sense. I haven't used any of the import modules yet but I will start to look at them.
Explicitly matching on those particular two relevant elements works well in this particular problem, but in general, I'd prefer using drop and take to avoid having to unwrap and re-wrap many individual variables.
@leftaroundabout: I agree: only in case the number of elements is low (and constant) this works well. Otherwise it is indeed better to use drop, take, etc. :)
The only thing I still don't understand, with my first code segment I'm trying to evaluate the elements to output a Boolean result. If I input that into the prelude it works.
0

Thanks again for all the advice, it is greatly appreciated. So I found out why my code wasn't working and it was because I was using the Haskell built in function "compare" as my function name. So as soon as I re named them they all check out.

Just to clarify my question was, To compare the second & third element of a id number eg P16201348. These elements indicate if two numbers are from the same year, 16, 17 etc..

The code I have gone with is this,

pnum :: Eq a => [a] -> [a] -> Bool

pnum (:xs)(:ys) = xs !! 1 == ys !! 1 && xs !! 2 == ys !! 2

So, I use underscore on the head of each list as this element isn't important. I then compare the elements that I need and check them for equality.

I mean this may not be the best and most efficient way to do this so please do let me know if you think not.

Thanks

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.