Haskellのお勉強 その4
concat関数
{-concat関数の型-} concat :: [[a]] -> [a]
main = do cs <- getContents putStr $ expand cs expand :: String -> String expand cs = concat $ map expandTab cs expandTab :: Char -> String expandTab c = if c == '\t' then " " else [c]
concat関数は、リストのリストxsを連結して1つのリストにする。
要は、concat関数ってのはリストを一重減らす作用があるということですな。
パターンマッチ
tabStop :: Int tabStop = 8 main = do cs <- getContents putStr $ expand cs expand :: String -> String expand cs = concatMap expandTab cs expandTab :: Char -> String expandTab '\t' = replicate tabStop ' ' expandTab c = [c]
パターンマッチ機能により、ある特定の引数に対する値を分けて書くことが出来る。
パターンマッチを書く場合、特定性の高い順番に書かないとうまく機能しない。
例にあるexpandTab関数のパターンマッチの順番を入れ替えると、
引数が'\tであっても、 「replicate tabStop ' '」という関数が適用されなくなってしまう。
また、関数定義で参照されない任意の引数は「_」で表現される。
リストに対するパターンマッチ
{-map関数の定義-} -- 関数の型 map :: (a -> b) -> [a] -> [b] -- 定義1 map f [] = [] -- 定義2 map f (x : xs) = f x : map f xs
定義1の「」は、空リストにだけマッチするパターンで、
定義2の「(x : xs)」は、空リスト以外のリストにマッチするパターンである。
つまり、「(x : xs)」は、要素が1つ以上あるリストにマッチする。
マッチしたときには、リストの最初の要素にxが束縛され、第2要素以降のリストにxsが束縛される。
例えば、[1,2,3,4,5]に(x : xs)というパターンマッチをさせると、
xの値は1で、xsの値は[2,3,4,5]となる。また、[7]にマッチさせた場合、xが7となり、xsがとなる。
また、定義2は次のように解釈することができる。
map f (x : xs) = ((f x) : (map f xs))
つまり、リストの第1要素にfを適用しつつ、残りの第2要素以降は再帰で処理している。
また、「:」はリストを生成する演算子で、リストに対するパターンマッチでは、
(x : xs)がリストを先頭要素とそれ以降の要素に分解したが、
関数定義の中で(y : ys)を使うと逆の意味となり、リストysの先頭にyを追加したリストを生成する。
例えば、1 : [2,3,4,5]の値は[1,2,3,4,5]となり、7 : []の値は[7]となる。
map関数は、結果的に、第1要素にfを適用したものと、
残りの要素にfを適用したものからリストを生成したものを返す。
練習問題:標準入力の'a'と'A'を入れ替えるコマンド
{-swapa-} main = do cs <- getContents putStr $ map expandCap cs expandCap :: Char -> Char expandCap 'a' = 'A' expandCap 'A' = 'a' expandCap c = c