Shane
Shane

Reputation: 2375

How to apply use map in this instance?

I have a list of months and a string. I want to check to see if any of the months are in the string. I also have a function that takes searches a string for a word. Do I have to rewrite that function or is this possible with some form of map?

fullMons = ["january", "febuary", "march", "april", "may", "june", "july", "september", "october", "november", "december"]

searchStrList :: String -> [String] -> Bool
searchStrList str strList = elem (map toLower str) $ convertToLower $ words strList

How can I utilize these functions to do something like this:

check :: String -> Bool 
check str = searchStrList "january" || searchStrList "febuary" || ...

Still just learning Haskell, so any other comments on my code is appreciated. Thanks

Upvotes: 3

Views: 133

Answers (3)

sbenitezb
sbenitezb

Reputation: 535

data Month = January | February | March | April |
             May | June | July | September | October | November | December
             deriving (Eq, Show)

months = [March, December, April]
april = April `elem` months

Use the types, and from there convert from those types to the string representation, as in:

show April

Upvotes: 0

ehird
ehird

Reputation: 40797

Note that fullMons isn't a function but a list, and searchStrList doesn't type; words takes a single strings, but you apply it to a list of strings.

I guess what you're trying to do is find whether the words of a string contain any of the month names in fullMons. Let's try and derive a solution step by step. The first thing we want to do is apply words to our input string; that gets us a list of strings.

words str :: [String]

Then we want to find out whether any of the elements of words s is a month name. There's a function any:

any :: (a -> Bool) -> [a] -> Bool

So, our solution should look like

check str = any ??? (words str)

and all we have to do is figure out the ???. The elem function lets us check whether an element in a list:

elem :: (Eq a) => a -> [a] -> Bool

In this case, the list should be the list of months, and the element we're searching for should be the word of the string. So, to fill in the blank:

check :: String -> Bool
check str = any (\word -> word `elem` fullMons) (words str)

(Note: foo `op` bar is just op foo bar; a lot of operators are designed to be written and read this way.)

We can make this simpler and more idiomatic by getting rid of the parameter:

check :: String -> Bool
check = any (\word -> word `elem` fullMons) . words

This means that we apply words to the input, and then apply any (\word -> elem word fullMons) to the result of words. You could simplify this further to:

check :: String -> Bool
check = any (`elem` fullMons) . words

(i.e., "do any of the elements of the words of our input appear in fullMons?")

but that isn't necessary.

I think the original solution you were trying to get at was to check each month name on the entire string in turn. To do this, we just need to flip the control structure a bit:

check :: String -> Bool
check str = any (\word -> word `elem` ws) fullMons
  where ws = words str

(i.e., "do any of the elements of fullMons appear in words str?")

Upvotes: 9

Ben James
Ben James

Reputation: 125307

You can use the any function to check if a predicate is true for any member of a list.

Here I have used the isInfixOf function from Data.List to make the predicate:

check :: String -> Bool
check str = any (`isInfixOf` str) fullMons

Upvotes: 3

Related Questions