Friday, April 25, 2014

[ffuprlwq] Counting

countWith :: [a] -> [[a]];
countWith l = [] : liftM2 (flip (:)) (countWith l) l;

Enumerates all the length-zero lists, then all the length-1 lists, then the length-2 lists, and so on, for a given list of elements (the "digits"). Vaguely inspired by Perl's .. operator which creates a list, e.g., for("a".."zzz"). Unlike Perl, the lists increase little-endianly.

> countWith "01"
["", "0", "1", "00", "10", "01", "11", "000", "100", "010", "110", "001", "101", "011", "111", "0000", "1000", "0100", "1100", "0010", "1010", "0110", "1110", "0001", "1001", "0101", "1101", "0011", "1011", "0111", "1111", "00000", "10000", "01000", "11000", "00100", "10100", "01100", "11100", "00010" ...

Here is a more understandable way of writing it. The list is used as the nondeterminism monad.

countWith l = [] : do {
  t <- countWith l;
  h <- l;
  return $ h:t;
};

2 comments :

Unknown said...

If counting is the intention, this might produce more natural results:

countWith' :: [a] -> [[a]]
countWith' ds = let xs = [ x ++ [d] | x <- [] : tail xs, d <- ds ] in xs

> countWith' "01"
["0", "1", "10", "11", "100", "101", "110", ...

This produces the results in big-endian order, like Perl and English, and (unlike Perl) omits duplicate "zero" representations ("", "0", "00", "000", ...) in favor of a single "0". If [ds !! n] ~ n, then (countWith' ds !! m) ~ m in big-endian place-value notation with base (length ds).

Ken said...

I probably should have mentioned the original motivation was to search for printable strings with special properties: http://kenta.blogspot.com/2014/02/weaylgfy-ascii-hashes.html.