سؤال

I am converting the zxcvbn password strength algorithm to Haskell.

I have two functions that check for all characters being ASCII and that a brute force attack is possible:

filterAscii :: [String] -- ^terms to filter
            -> [String] -- ^filtered terms
filterAscii = filter $ all (\ chr -> ord chr < 128)

and

filterShort :: [String] -- ^terms to filter
            -> [String] -- ^filtered terms
filterShort terms = map fst $ filter long $ zip terms [1..]
  where long (term, index) = (26 ^ length term) > index

I composed these into a single function:

filtered :: [String] -- ^terms to filter
         -> [String] -- ^filtered terms
filtered = filterAscii . filterShort

I now have need to compose these with a third filter to check if the terms are not null:

filter (not . null) terms

It has occurred to me that I am creating a chain of filters and that it would make more sense to create a single function that takes a list of filter functions and composes them in the order given.

If I recall from my reading, this is a job for an applicative functor, I believe. Can I use applicatives for this?

I am not sure how to handle the filterShort function where I need to zip each item with its one-based index before filtering.

هل كانت مفيدة؟

المحلول

You can use the Endo wrapper from Data.Monoid to get a monoid instance that will allow you to use mconcat like so:

Prelude> :m + Data.Monoid
Prelude Data.Monoid> :t appEndo $ mconcat [Endo filterAscii, Endo filterShort]
appEndo $ mconcat [Endo filterAscii, Endo filterShort] :: [String] -> [String]

نصائح أخرى

In other words, you want :

filters :: [a -> Bool] -> [a] -> [a]
filters fs = filter (\a -> and $ map ($ a) fs)

But you should also know that a pipeline of filters is very likely to be optimized by GHC (as far as I know) anyway. So it may not be worth it to create this function. Note that there will be some problems with your filterShort since it's not a pure filter.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top