{-
岩崎(電通大)のプログラム

私も，4月号の Haskell の連載の第一回を読ませていただきました．
その中の車両のソート問題ですが，すべての関数について dec系とinc系の
二つのバージョンを用意 (同じようなコードが重複している) ところが
気になり，次のようなプログラムを作ってみました．

基本的には，「関係演算」を引数に持たせることにするのですが，
dec の中で inc を呼び，inc の中で dec を呼んだりすることがあるので，
関係演算 (二引数関数) をペアにして持ち歩くことにしました．
関数が First Class ですから，こういうことが簡単にできますね．
(ペアにせず，逆の関係を得たければ，not を合成して関数を作る，という
方法もありますが，再帰のネストが深くなると，not . not . not . ....
と，not が何重にもなってしまうところが気に入りませんでした．)

コードはずいぶん短くなったと思います．
-}

merge2 :: (Int -> Int -> Bool) -> [Int] -> [Int] -> [Int]
merge2 rel [] ys = ys
merge2 rel (x:xs) [] = x:xs
merge2 rel (x:xs) (y:ys) | x `rel` y = x : merge2 rel xs (y:ys)
                         | otherwise = y : merge2 rel (x:xs) ys

mergen :: (Int -> Int -> Bool) -> [[Int]] -> [Int]
mergen rel = foldl1 (merge2 rel)

decMergen = foldl1 (merge2 (>)) --- 動作確認用，本当はいらない
incMergen = foldl1 (merge2 (<)) --- 動作確認用，本当はいらない

sort :: (Int -> Int -> Bool, Int -> Int -> Bool) -> Int -> [Int] -> [Int]
sort (rel1,rel2) n cs
  | n == 2 =    mergen rel1 ([head cs]:[tail cs])
  | otherwise = mergen rel1 (xs:ys)
                where xs = reverse (sort (rel2,rel1) n2 (take n2 cs))
                      ys = move (rel1,rel2) n2 (drop n2 cs)
                      n2 = n `div` 2

decSort, incSort :: Int -> [Int] -> [Int]
decSort = sort ((>),(<))
incSort = sort ((<),(>))

move :: (Int -> Int -> Bool, Int -> Int -> Bool) -> Int -> [Int] -> [[Int]]
move rels n cs | n == 2    = [head cs]:[tail cs]
               | otherwise = xs:ys
                             where xs = sort rels n2 (take n2 cs)
                                   ys = move rels n2 (drop n2 cs)
                                   n2 = n `div` 2

decMove, incMove :: Int -> [Int] -> [[Int]]
decMove = move ((>),(<)) --- 動作確認用，本当はいらない
incMove = move ((<),(>)) --- 動作確認用，本当はいらない

cars8 :: [Int]
cars8 = [3,1,4,5,2,6,7,0]

