I was happy with my shell script that needed to generate alphanumeric combinations of length N (in this case, 3)
for i in {a..z}{a..z}{a..z}; do ...
Now I became less happy when I needed alphanumeric combinations (specially if I choose a larger value for N)
for i in {0..9}{a..z}{a..z} \
{a..z}{0..9}{a..z} \
{a..z}{a..z}{0..9} \
{a..z}{a..z}{a..z} \
{0..9}{0..9}{a..z} \
{0..9}{a..z}{0..9} \
{a..z}{0..9}{0..9} \
{0..9}{0..9}{0..9}; do ...
So I decided to write it in Haskell:
import Data.List
c 0 _ = [[]]
c n xs = [ y:ys | y:xs' <- Data.List.tails xs, ys <- c (n-1) xs']
main = sequence_ . map putStrLn . c 3 $ ['a' .. 'z'] ++ ['0' .. '9']
Now, I couldn't find a way to incorporate the above code in my shell script, so I had to reduce it to a one-liner to run with ghc -e
, finally giving me the code I have right now:
for i in $(ghc -e "
let c n l = if n == 0 then [[]] else \
[y:s | y:q <- Data.List.tails l, s <- c (n-1) q] in
sequence_. map putStrLn . c 3 $ ['a'..'z'] ++ ['0'..'9']"); do ...
Now, I actually like this style (elsewhere I have inline calls to awk too, etc). But I think this code is too big and too ugly; for example, I'm using if n == 0
instead of guards, etc. Haskell is supposed to be a lot more concise than that.
My only requirement is that I may want to change the length to be larger than 3, but also ['a'..'z'] ++ ['0'..'9']
to another set (perhaps to include - or _).
if n == 0 .. else ..
by turning the let binding into a where binding, but I couldn't figure out how to write it in one line. \$\endgroup\$runghc --
. \$\endgroup\$