{- KnuthのAlgorithm B : cycleperm.hs -}

{- see page 173 of The Art of Computer Programming, Vol.1 3rd ed. -}
{- Algorithm B (Multiply permutations in cycle form) -}

import List

perms :: [String]
perms = ["acfg","bcd","aed","fade","bgfae"]

goesTo :: [String] -> (String, String)
goesTo ss = (allchar, allgo)
  where allchar = sort (nub (foldl1 (++) ss))
        allgo = fst (foldr go (allchar, '?') (map reverse ss))
        go [] (ps, o) = (a ++ (o: tail b), o')
          where [i] = elemIndices '?' ps
                (a,b) = splitAt i ps
                o' = head b
        go (c:cs) (ps, o) = go cs (ps', o')
          where [i] = elemIndices c allchar
                (a,b) = splitAt i ps
                ps' = a ++ (o: tail b)
                o' = head b
{- Table 2
     ( a c f g ) ( b c d ) ( a e d ) ( f a d e ) ( b g f a c )
a ->|d d a a a a|a a a a a|a a d d d|d d d e e e|e e e e e a a
b ->|c c c c c c|c c g g g|g g g g g|g g g g g g|g g b b b b b
c ->|e e e d d d|d d d c c|c c c c c|c c c c c c|c c c c c c c
d ->|g g g g g g|g ? ? ? d|d ? ? ? b|b b b b d d|d d d d d d d
e ->|b b b b b b|b b b b b|b b b a a|a ? ? ? ? b|b ? ? ? ? ? e
f ->|f f f f e e|e e e e e|e e e e e|e e a a a a|a a a a f f f
g ->|a ? ? ? ? f|f f f f f|f f f f f|f f f f f f|f f f g g g g

Main> goesTo perms
("abcdefg","dcegbfa")

goを外に出して, reverseしたものを使い, 一歩ずつ実行する

go :: String -> (String, Char) -> (String, Char)
go [] (ps, o) = (a ++ (o: tail b), o')
  where [i] = elemIndices '?' ps
        (a,b) = splitAt i ps
        o' = head b
go (c:cs) (ps, o) = go cs (ps', o')
  where [i] = elemIndices c "abcdefg"
        (a,b) = splitAt i ps
        ps' = a++(o:tail b)
        o' = head b

Main> reverse (map reverse perms)
["eafgb","edaf","dea","dcb","gfca"]

Main> go "eafgb" ("abcdefg", '?')
("egcdbaf",'?')
Main> go "edaf" ("egcdbaf",'?')
("dgcbaef",'?')
Main> go "dea" ("dgcbaef",'?')
("agcdbef",'?')
Main> go "dcb" ("agcdbef",'?')
("acdgbef",'?')
Main> go "gfca" ("acdgbef",'?')
("dcegbfa",'?')
-}

