1
votes

I'm trying to check if a String is included in a list of Strings and, if it is, I want to return the rest of the Strings in the list AFTER the String has been located.

My issue is that I would normally use recursion to find the String within the list and then return everything after; however, I'm new to Maybe statements so I'm not sure if recursion is the best way to check and return what I want.

strReturn :: String -> [String] -> Maybe [String] 
strReturn x (y : ys)
  | x == y = Just ys
  | x /= y = Nothing

The code I've written only checks the head of the list; I'm unsure how to check the rest of the list within the syntax of a Maybe statement - and I want to return everything AFTER the string. This works in all the right way but only for the head. If the String is anywhere but the head it won't see it or return anything.

1
Hint: the function should result in Nothing if the list argument is empty, and if it's non-empty but the head doesn't match then the function should recurse. - Robin Zigmond
I'm not sure how to use recursion within the syntax of a Maybe statement. The just statement would have to be recursive but how do you write a recursive Just statement? - user9660393
Not sure what you mean by "recursive Just statement" (and Haskell doesn't have statements anyway, andJust x is just a value). You're recursing on the list, not a Maybe value - just use pattern matching and guards, every right hand side is either a Just value, Nothing or a recursive call. (What you have above is a good start, you've just forgotten both the recursion and the empty-list case.) - Robin Zigmond

1 Answers

4
votes

As @RobinZigmond has said, recursion will work fine here, and there's nothing too special about using recursion with Maybe values. Don't think of Nothing and Just as "statements". Nothing is a value, and Just ["a","b","c"] is a value, and a recursive function that returns such values is written and used in much the same way as a recursive function that returns integers.

Spoilers below, but try doing it yourself first, with a further hint. In your definition, Nothing is a value of type Maybe [String]. You'd like to replace it with a recursive call to strReturn, and the return type of strReturn is Maybe [String], which is exactly the type you need! No Just, "recursive" or not, is needed -- just try replacing Nothing directly with a strReturn call that typechecks.

If you still can't figure it out, read on...

Taking your strReturn as a starting point, note that, if x /= y, then you want to keep looking in the rest of the string, so that case should be:

strReturn x (y : ys) | x /= y = strReturn x ys

This type-checks fine. The strReturn call on the left needs to return a value of type Maybe [String], and fortunately the recursive strReturn call on the right has exactly that type, so no problem.

The only problem with the code now is that it'll crash if the string isn't found, because eventually you'll run out of strings, and the recursive call:

strReturn "whatever" []

won't match the pattern in the definition. You need to add a case that states that, if the end of the list is reached (obviously without finding the string, or we would have stopped by now), we need to return Nothing:

strReturn _ [] = Nothing

The full definition is:

strReturn :: String -> [String] -> Maybe [String]
strReturn _ [] = Nothing
strReturn x (y : ys)
  | x == y = Just ys
  | otherwise = strReturn x ys

Note that it's slightly better practice to use otherwise than x /= y. This will both avoid an unnecessary check in the compiled code and avoid a warning that you'd get if you compiled with -Wall (which you should!) about non-exhaustive patterns. The compiler isn't quite clever enough to figure out that x /= y will always succeed if x == y has failed. (For user-defined datatypes, this could technically be false.)