**strong :: String -> Bool**

which returns

**True**iff the string passed to it is a "strong" password, which for purposes of the assignment means

- it's at least 15 characters long
- it includes upper case letters
- it includes lower case letters
- it includes digits

Easy enough to write, especially if you

**import Data.Char**, but the lesson is about higher-order functions, and you're urged to use the things taught in the lesson (among which are the character classification functions in**Data.Char**). So it occurred to me that it would be good to write the function in a way that makes it easy to add other constraints--perhaps it shouldn't be in some list of bad password choices, say.
So, we'd like to write it to take a list of

**String -> Bool**, apply them to the**String**, and confirm that they all return**True**. The lesson teaches about**all**and about**map**, but we don't want**map**here.**map :: (a -> b) -> [a] -> [b]**

but we want

**wonkyMap :: [a -> b] -> a -> [b]**

An obvious implementation is

**wonkyMap [] _ = []**

**wonkyMap (f:fs) x = (f x) : (wonkyMap fs x)**

though I'm sure it can be written more elegantly as a fold.

(UPDATE: Duh... list comprehensions are your friend.

just as you could define

There's a pleasing symmetry there.)

Then you have

(UPDATE: Duh... list comprehensions are your friend.

**wonkyMap fs x = [f x | f <- fs]**just as you could define

**map f xs = [f x | x <- xs]**There's a pleasing symmetry there.)

Then you have

**strong password = all $ wonkyMap constraints password**

**where constraints = [(> 15) . length,**

**any isUpper,**

**any isLower,**

**any isNumber]**

OTOH, someone has to have come up with

UPDATE: Oops... make that

**wonkyMap**before--and given it a better name. Hoogling the signature, though, didn't turn up anything. Does it look familiar to anyone?UPDATE: Oops... make that

**(>= 15) . length**