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

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

Haskell H99 Question 11

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

import Data.List

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

--自分で作った解答
encodeModified :: Eq a => [a] -> [ListItem a]
encodeModified xs = map (listToAmount) (group xs)
	where
		listToAmount :: Eq a => [a] -> (ListItem a)
		listToAmount (x:xs)
			| length (x:xs) > 1	= Multiple (length (x:xs)) x 
			| otherwise 		= Single x

--模範解答
--Question 9 からの引用
encode xs = map (\x -> (length x,head x)) (group xs)

encodeModified' :: Eq a => [a] -> [ListItem a]
encodeModified' = map encodeHelper . encode
    where
      encodeHelper (1,x) = Single x
      encodeHelper (n,x) = Multiple n x


頑張ってみたのですが、どうしてもdata型を作ることができなかったので答え見ました。。
データ型とか、インスタンスとか型クラスとか、あんまり理解できていないようなので、どこかで勉強しないと。

データ型の宣言

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

ListItemの宣言です。見たらこういうもんかと思いますが、こういう形に自分で作ることはできませんでした。
ListItem aはSingle aかMultiple Int aという形をとるという単純なものですが、型変数に任意の型クラスを適用とすると構文エラーになってしまって断念。
そういうことはできないのかしら。。
derivingとは派生などという意味らしいです。構文については、そのうちしっかり勉強して書きます。

自分で作った解答

encodeModified :: Eq a => [a] -> [ListItem a]
encodeModified xs = map (listToAmount) (group xs)
	where
		listToAmount :: Eq a => [a] -> (ListItem a)
		listToAmount (x:xs)
			| length (x:xs) > 1	= Multiple (length (x:xs)) x 
			| otherwise 		= Single x

第9問のやり方を参考にして、mapとgroupを使いました。
map用にリストを引数にListItemを返す関数を作り、その中で条件によってSingleかMultipleを返すようにしました。
まあまあいいじゃんと思いましたが、模範解答では関数合成を使用していました。そっちのほうがエレガントに見えますね。

模範解答

--Question 9 からの引用
encode xs = map (\x -> (length x,head x)) (group xs)

encodeModified' :: Eq a => [a] -> [ListItem a]
encodeModified' = map encodeHelper . encode
    where
      encodeHelper (1,x) = Single x
      encodeHelper (n,x) = Multiple n x

以下のように関数が定義されています。

encode :: Eq t => [t] -> [(Int, t)]
map encodeHelper :: [(Int, a)] -> [ListItem a]  (ちなみに、encodeHelper :: (Int, a) -> ListItem a)

これにより、encode の戻り値をそのままmap encodeHelperにつなげることができますね。