Haskellお勉強会第6日目まとめ


"Real World Haskell"の第4章の5節まで読み終えました。

Real World Haskell―実戦で学ぶ関数型言語プログラミング

Real World Haskell―実戦で学ぶ関数型言語プログラミング

Real World Haskell 第4章の読書メモ

  • 外部とのやり取りを行う場合はdo記法による「アクション」を使うんだ。
  • 「<-」はdoブロックの中での代入みたいなもんだ。微妙に違うが最初は気にすんな
  • break 関数は最初にfalseを受け取った時点で終了するぞ
  • OSの違いによる改行コードの違いには気をつけよう
  • python の改行は良く出来ている!
  • デカいコードをいきなり書くとテストしにくいから小さいところから始めよう!結果として読みやすいコードになるぞ!
  • 関数をバッククォートで囲むと中置関数として使えるぞ!読みやすくなったりするけど適切に使おう
  • length関数は線形時間がかかるぞ!空リストの判定にはnull関数を使おう! パターンマッチも役立つぞ!
  • Boolのリストにはand, or関数とかもあるぞ!地味に便利
  • all, anyもよろしくな!

ここが気になる

  • break 関数みたいな(a -> Bool) -> [a] -> ([a], [a])でリストの最後まで走査する関数は何じゃろ? -> partitionだよ
  • spanとpartitionが紛らわしいわ

練習問題

  • 1 head, tailなどの関数の「安全版」を作れ
safeHead [] = Nothing
safeHead xs = Just(head(xs))

以下略

  • 2 述語をと任意の方のリストを取り、述語がFalseを返す要素で入力リストを分割するsplitWidthxを作れ
splitWith :: (a -> Bool) -> [a] -> [[a]]
splitWith _ [] = []
splitWith pred xs = 
  let (pre, suf) = span pred xs
  in pre : case suf of
             [] -> []
             _  -> splitWith pred (tail suf)
> splitWith even [1,1,1,2,3,3,3,4,5]
[[],[],[],[2],[],[],[4]]

みたいなキモい事になったので、

splitWith :: (a -> Bool) -> [a] -> [[a]]
splitWith _ [] = []
splitWith pred xs = 
  let (_, dropped) = break pred xs
  in let (pre, suf) = span pred dropped
  in pre : splitWith pred suf

と変えたら

> splitWith even [1,1,1,2,3,3,3,4,5]
[[2],[4][]]

みたいになってしまったでござる。

splitWith :: (a -> Bool) -> [a] -> [[a]]
splitWith _ [] = []
splitWith pred xs = 
  let (_, dropped) = break pred xs
  in case  dropped of
       [] -> []
       _  -> let (pre, suf) = span pred dropped
             in pre : splitWith pred suf
  • 3 入力各行の最初の単語を印字するプログラムを作れ
interactWith function inputfile outputfile = do
  input <- readFile inputfile
  writeFile outputfile (function input)

main =  mainWith myFunction
  where mainWith function =  do
          args <- getArgs
          case args of
            [input, output] -> interactWith function input output
            _  -> putStrLn "error"

        myFunction x = 
          let line = lines x
          in firstWords line

        firstWords line = 
          case line of
              [] -> []
              _  -> firstWord (head line) ++ ['\n'] ++ firstWords (tail line)

        firstWord l =
          case l of 
            [] -> []
            _  -> head (splitWith isChar l)

        isChar c = c /= ' '