むずかしめのパソコン勉強の記録

計算機科学とか関数型言語とか

Haskell H99 Question 12

http://www.haskell.org/haskellwiki/99_questions/11_to_20

問題12
問題の日本語訳

連長圧縮のリストを復号しなさい。
問題11で明示された通りに作られた連長圧縮コードが与えられる。その展開した版を作成しなさい。

data ListItem a = Single a | Multiple Int a deriving (Show)

decodeModified :: [ListItem a] -> [a]
decodeModified [] = []	-- (1)
decodeModified ((Single x):xs) 		= x : decodeModified xs  --(2)
decodeModified ((Multiple 1 x):xs) 	= x : decodeModified xs  --(3)
decodeModified ((Multiple n x):xs) 	= x : decodeModified ((Multiple (n-1) x):xs)  --(4)

まあまあよくできたと思うけどやっぱり模範解答は全然違うことが書いてありました。(後述)
パターンマッチングというやつはここまでできるんですねー、関心。

(1) 空だったら空のリストを返す。終点
(2) もし先頭要素がSingleだったら、先頭に文字をくっつけて後続に対して再帰
(3) もし先頭要素がMultipleで長さが1だったら(2)と同じ処理
(4) もし先頭要素がMultipleで長さが1以外だったら、先頭に文字をくっつけて長さを減らしてもう一回

模範解答

http://www.haskell.org/haskellwiki/99_questions/Solutions/12

concatMapを使っていますね。確かに結構きれい。
concatMapは、こんなのです。

concatMap :: (a -> [b]) -> [a] -> [b]   -- Defined in `GHC.List'

aのリストに第一引数の関数を当てるけど、そのままだと[[b],[b],[b]]みたいになっちゃうから中のかっこを外して[b]にするってやつだな。
ちょっと試しに使ってみる。
まず非リストな何かを取ってリストを返す関数を適当に作ってみて、

naturalNumberTill n = naturalNumberTill' 1 n
	where 
		naturalNumberTill' x n
			| x > n 	= []
			| otherwise	= x : naturalNumberTill' (x+1) n 

それを使って実行してみる。

*Main> :t naturalNumberTill
naturalNumberTill :: (Num a, Ord a) => a -> [a]

*Main> map naturalNumberTill [3,4,5]
[[1,2,3],[1,2,3,4],[1,2,3,4,5]]

*Main> concatMap naturalNumberTill [3,4,5]
[1,2,3,1,2,3,4,1,2,3,4,5]

なるほど。