しりとり

勉強会でのネタ。与えられた語彙を全て使ってしりとりができるかどうかを判定するもの。
shiritori は無理に StateT を使ったもの。
shiritori2 は、順列を作ったあとにしりとりができる並びのものだけを取り出すという素直な実装。

import System (getArgs)
import Control.Monad.State
import Data.List (delete)

-- solution 1
shiritori :: Int -> StateT ([String], [String]) [] ()
shiritori 0 = return ()
shiritori n =
    do (w:ws, v) <- get
       lift [(a:w:ws, delete a v) | a<-v, null w || last w == head a] >>= put
       shiritori (n-1)
main = do args <- getArgs
          mapM_ (putStrLn.unwords.reverse.fst) $
                execStateT (shiritori $ length args) ([""],args)

-- solution 2
perm l = perm' ([],l)
    where perm' (a,[]) = return a
          perm' (a,b)  = do c <- b
                            perm' (c:a, delete c b)
shiritori2 ws = filter connectable $ perm ws
    where connectable []      = True
          connectable [a]     = True