Haskellの基礎(3) モジュールと総合演習

4.2 総合問題

対になってる関数

遂になってる関数としてまとめられていて分かりやすかったので。

lines :: String -> [String]
unlines :: [String] -> String


linesして、行単位で処理してからunlinesで文字列にする。
確かにイディオムとして考えるとよい感じですね。

head :: [a] -> a
tail :: [a] -> [a]


こちらも対になってて分かりやすいんだけど、なぜ引数に空リストを指定すると実行時エラーになるんだろう?
今までの流れからすると空リストを返すと思った(headは無理ですけど)。
これらの関数を使う時は空リストチェックが必要になるんだろうなぁ、と思いつつ。

where節について

where節は、他の入門サイトなどを眺めていてよく理解出来なかったものの一つ。
でも本書の説明はとても分かりやすい♪


ある関数の中だけで使える関数を定義する時に利用するんですね。
スコープがある関数の中というわけですね。
あとちょっと気になったのは、patternという変数。
where節に定義された関数からは、where節がかかっている関数内の変数を見ることが出来るんですね。


`isPrefixOf`という書き方について

こういう考え方はとても面白いです。
C言語にはない考え方ですね。分かりやすさによって、文法を選べるとは。
C言語に慣れてしまうと、

xs `isPrefixOf` ys


よりも

isPrefixOf xs ys


の方が分かりやすく感じてしまうところに若干寂しさを感じてしまいますが…。

Prelude> replicate 4 ' '
"    "
Prelude> 4 `replicate` ' '
"    "


これは論外ですね(笑)。

4.3 本章のまとめ

4.4 練習問題

問題1

上で書いたイディオム(lines+unlines)を使うんですね。
まずは自力でおりゃっ!…の前にちょっと実験。

Prelude List> sort [1,3,2]
[1,2,3]
Prelude List> sort ["abc","def","bcd"]
["abc","bcd","def"]


なるほどぉ、sortは値だけじゃなく、文字列などのリストもオッケーなんですね。
そりゃそうか、関数の型にそんな制約ないからね。
ということで、こんな感じになりました。

import List

main = do cs <- getContents
          putStr $ sortlines cs

sortlines :: String -> String
sortlines cs = unlines $ sort $ lines cs


うん、いい感じ♪

問題2

これももちろんlines→unlinesのイディオムを使います。
でもこれはそんな簡単じゃないなぁ。ちょっと考えてみる。


List.group関数で同じ要素がリストにまとめられるので、その各リストの先頭要素を取り出して要素にすればいい。
この方針でちょっと実験。

Prelude List> map head $ group ["abc","abc","bcd","bcd","cde"]
["abc","bcd","cde"]


よしよし、うまくいきそうだ。この勢いで作ってみました。

import List

main = do cs <- getContents
          putStr $ uniq_lines cs

uniq_lines :: String -> String
uniq_lines cs = unlines $ map head $ group $ lines cs


テストファイルを使って、こんな感じでやってみました。

$ cat test.txt
abc
abc
bcd
bcd
abc
cde
$ ./uniq < test.txt
abc
bcd
abc
cde


おぉ、ちゃんと隣り合う同じ行が一つにまとまってる♪