2008年04月15日

[Haskell] ローテイト関数を作る

  
与えられたリスト内の要素を右にスライスする rrotate、左にスライスする lrotate関数を作れ。

新人君用のC#の問題は、画面フォーム上のtextBoxの内容を、スライドさせるというものだったが、内容を変更。

rrotateの場合、[1,2,3,4,5]を与えれば、[5,1,2,3,4]が返る。

lrotateは簡単だ、

lrotate :: [a] -> [a]
lrotate [] = []
lrotate (x:xs) = xs ++ [x]

先頭要素を、後ろにくっつければ良い。++ は、リスト同士の結合演算子。

一方、rrotateは、手こずった。
なんとかできたのが、以下のコード。

rrotate :: [a] -> [a]
rrotate [] = []
rrotate list = last list : take (length list - 1) list

最後の要素を取り出し、: 演算子を使い最後を除いたリストと結合している。
うーーん、美しくない。
もっと違った方法があると思うのだが...

で考えたのが、最後の要素を除いたリストを取得する lead関数を作るというもの。

rrotate :: [a] -> [a]
rrotate [] = []
rrotate xs = last xs : lead xs

と書ければ、コードの意図が読み取りやすくなる。
そこでtakeや、length関数を使わずに、lead関数を書いてみる。

lead :: [a] -> [a]
lead [] = []
lead (x:[]) = []
lead (x:xs) = x : lead xs

これも、いまいちだな。まあしょうがないか。


この記事へのコメント
美しいかはわかりませんが、こんなのはいかがでしょうか。

rrotate [] = []
rrotate list = let x:xs = reverse list in x : reverse xs

同じ考え方をlrotateにも当てはめると、

lrotate [] = []
lrotate (x:xs) = reverse $ x : reverse xs

こちらはわかりにくいですね。w
Posted by nsharp at 2008年04月16日 10:40
↑のコードを書き換えてみたら、なんとなくきれいになりました。

revTail [] = []
revTail (x:xs) = x : reverse xs

lrotate = reverse . revTail

rrotate = revTail . reverse
Posted by nsharp at 2008年04月16日 12:20
nsharp さん。
おおっ。ローテイトのアルゴリズムにreverseが使えるんだ。
頭の体操になります。
Posted by Gushwell at 2008年04月16日 20:31
 

この記事へのトラックバックURL