0

I have two strings; one main string, and another one of two chars (eg. "aa").

I want to see if my main string contains the second string and print its indices in the main string.

I have tried to zip the main string with itself so I can inspect every combination of the letters that comes after each other (eg. "abab" = (a,b) (b,a) (a,b)). I zip these tuples with [1..] to have the correct index where the matching string might start ((a,b) 0). Then I take fst(fst h) to extract the first letter from the tuple and see if it matches the first letter of my secondary string. If it does not find any matches, it should run again on the rest of the main string (xs). I used where to declare variable h as head(locateZip x:xs)

locate (x:xs) (y:ys) = if fst(fst h) == y && snd(fst h) == ys then snd h else locate xs (y:ys)
                 where h = head(locateZip x:xs)
locateZip xs = zip(zip xs(tail xs)) [0..]

snd h is used to print the index of the tuple.

It should return something like this:

locate "aabba" "aa" 
0

locate "bbaab" "aa"
2

I know this might look unusual but I am still new and having trouble understanding the errors I get and what works and what doesn't.

I get an error on h saying:

Couldn't match expected type: ((Char, b2), b3) with actual type: [((b0, b0), b1)]

Is the where statement used correctly for this function?

3
  • Could you provide an use case of the locate function? Is it something like: > locate "abcaad" "aa" returning a tuple, for instance, like (3,4), supposing string position started with zero? Commented Sep 16, 2021 at 15:12
  • I made an edit now :) Commented Sep 16, 2021 at 15:22
  • I just need it to work with the first index. So in your example it only has to output 3 Commented Sep 16, 2021 at 15:22

1 Answer 1

1

I've found three problems in your code. Two were syntactical and one is a logical problem. I've tried to change as little as possible.

First of all, in the where statement, you must use () with ":" operator:

where h = head(locateZip (x:xs))

In your code Haskell was inferring a different type for locateZip function.

Second, in the comparison below

snd(fst h) == ys

ys is a list and not a character. This is because ":" operator split a list into the first element and the tail of a list, as is happening in the beginning of the function:

locate (x:xs) (y:ys)

Now, the logical problem. Using where, you are generating a zip list whenever locate function is called. However, whenever locateZip function is called, indexes are regenerated. Then, in your original idea, locate function will output 0 whenever the pair is found.

There's also another problem, since your locate function does not have a guard, in the beginning, to stop recursion. Well, after some changes, the code below seems to work as you expected:

locate [] _ = -1
locate phrase pair = locate_aux phrase pair (locateZip phrase)
locate_aux _ _ [] = -1
locate_aux (x:xs) (y1:y2:ys) h = 
    if (fst (fst (head h)) == y1) && (snd (fst (head h)) == y2) then 
        snd (head h) 
    else
        locate_aux xs (y1:y2:ys) (tail h)
locateZip xs = zip(zip xs(tail xs)) [0..]
Sign up to request clarification or add additional context in comments.

5 Comments

so in your code h is locateZip phrase, meaning instead of having it as where statement, you made a help function to enable it as an input? As my "pair" is only two letters, is using y1:y2:ys the same as using head ys for y1 and last ys for y2?
Also, thank you for going step by step through it :) It has been frustrating not understanding
One last question, I forgot that a word might have several instances of the pair. How can I store the index for the pair and print all of them as a list? eg: "aabbaa" "aa" [0,4]
Operator ":", when used before "=" symbol (function signature), forces a pattern matching against arguments passed in the function call. When we use "y:ys", y is the first element and ys is the rest of the list without the first element. So, you can't compare ys with a character. An alternative is forcing at least two elements, like "y1:y2:ys". Since your problem is only restricted to a pair, using strings is convenient in function call, but we have to deal with it in function implementation. A better option could be defining a user type that has two characters and use it in your function.
About your last question, you can change locate and locate_aux to return lists. When -1 is returned, you return an empty list ([]). For inserting elements, you may use recursion. When you find an instance (when if expression is True), you insert its index to a recursive call that look for other instances. That's it.

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.