ch04::RealWorldHaskell(1)


(p.88)ex.4-1
失敗する時はNothingを返せば良さそう。

-- ex.4-1
safeHead :: [a] -> Maybe a
safeHead xs
   | null xs   = Nothing
   | otherwise = Just (head xs)

safeTail :: [a] -> Maybe [a]
safeTail xs
   | null xs   = Nothing
   | otherwise = Just (tail xs)

safeLast :: [a] -> Maybe a
safeLast xs
   | null xs   = Nothing
   | otherwise = Just (last xs)

safeInit :: [a] -> Maybe [a]
safeInit xs
   | null xs   = Nothing
   | otherwise = Just (init xs)
Main> head []
*** Exception: Prelude.head: empty list
Main> safeHead []
Nothing
Main> tail []
*** Exception: Prelude.tail: empty list
Main> safeTail []
Nothing
Main> last []
*** Exception: Prelude.last: empty list
Main> safeLast []
Nothing
Main> init []
*** Exception: Prelude.init: empty list
Main> safeInit []
Nothing
Main>


(p.89)ex.4-2

-- ex.4-2
splitWith :: (a -> Bool) -> [a] -> [[a]]
splitWith _ [] = []
splitWith pred (x:xs)
   | not (pred x) = splitWith pred xs
   | otherwise    = pre : (splitWith pred suf)
                    where pre = takeWhile pred (x:xs)
                          suf = dropWhile pred (x:xs)
Main> splitWith odd [0,1,2,2,3,3,3,4,4,4,4,5,5,5,5,5,6,4,2,0]
[[1],[3,3,3],[5,5,5,5,5]]
Main> splitWith even [0,1,2,2,3,3,3,4,4,4,4,5,5,5,5,5,6,4,2,0]
[[0],[2,2],[4,4,4,4,],[6,4,2,0]]

何だかイケテない気がする、もっとスマートな解法があるかも。


(p.89)ex.4-3

-- file: InteractWith.hs
-- 前提(CommandLineFramework)
import System.Environment (getArgs)

interactWith function inputFile outputFile = do
   input <- readFile input File
   writeFile outputFile (function input)

main = mainWith myFunction
   where mainWith function = do
            args <- getArgs
            case args of
               [input,output] -> interactWith function input output
               _ -> putStrLn "error: exactly two argument needed"
         -- myFunction = id
         myFunction = firstWord  -- myFunctionにfirstWordを指定する

-- ex.4-3
firstWord :: String -> String
firstWord input = unlines (firstWordList (lines input))

firstWordList :: [String] -> [String]
firstWordList [] = []
firstWordList (x:xs)
   | null (words x) = "" : firstWordList xs
   | otherwise      = head (words x) : (firstWordList xs)
$ ghc --make InteractWith
[1 of 1] Compiling Main          ( InteractWith.hs, InteractWith.o)
Linking InteractWith ...
$ cat input.txt
ex.4-3 test
sample sample
1 2 3

   bar
baz
foo bar baz
$ ./InteractWith input.txt output.txt
$ cat output.txt
ex.4-3
sample
1

bar
baz
foo
$


(p.89)ex.4-4

-- ex.4-4
-- (補助関数)
-- 行の最大長を取得
maxLineLength :: [String] -> Int
maxLineLength [] = 0
maxLineLength xs = maximun (map length xs)

-- 文字列の長さが引数の値になるようスペース(' ')で埋める
fillWithSpace :: Int -> String -> String
fillWithSpace len xs
   | length xs >= len = xs
   | otherwise        = fillWithSpace len (xs ++ " ")

-- 引数分の空文字を持つリストを返す
setBase :: Int -> [String]
setBase 0 = []
setBase n = [] : setBase (n - 1)

-- (ここから行列入れ替え処理)
-- 行列を入れ替える
change :: Int -> [String] -> [String]
change n [] = setBase n
change n (x:xs) = zipWith (:) x (change n xs)

-- CommandLineFrameworkにchangeを渡す
-- ※myFunctionにchangeRowAndColを指定
changeRowAndCol :: String -> String
changeRowAndCol input = unlines (change maxLen filledList)
   where maxLen     = maxLineLength (lines input)
         filledList = map (fillWithSpace maxLen) (lines input)
$ ghc --make InteractWith
[1 of 1] Compiling Main          ( InteractWith.hs, InteractWith.o)
Linking InteractWith ...
$ cat sample.txt
Welcome to Ohr::Life.
Let's learn
Haskell Programming.
$ ./InteractWith sample.txt out.txt
$ cat out.txt
WLH
eea
lts
c'k
ose
m l
ell
 e
taP
orr
 no
O g
h r
r a
: m
: m
L i
i n
f g
e .
.
$

できた!