Haskell その1

Haskellでdiffを書けないものかと悪戦苦闘。


『やさしいHaskell入門』を読む。
http://www.sampou.org/haskell/tutorial-j/index.html
どこがやさしいのだ?w


こういうときはとにかく書いてみる。
まずはcatを書いてみる。

import System
 
cat :: String -> IO String
cat fn = do
  cs <- readFile(fn)
  return cs

cats :: [String] -> IO String
cats (x:xs) = do
  cs1 <- cat x
  cs2 <- cats xs
  return (cs1 ++ "\n" ++ cs2)

main = do
  args <- getArgs
  cs <- cats args
  putStr cs

ほんとはもっと試行錯誤したけど、コンパイル

$ /cygdrive/c/ghc/ghc-6.4.1/bin/ghc cat.hs

コンパイルは出来た。
しかし、あやすぃ。とくに再帰させてるつもりのcatsが。
でも動かす。

$ ./main.exe cat.hs
main.exe: cat.hs:(9,0)-(12,28): Non-exhaustive patterns in function cats

だよなぁ、リストが空のとき:: [String] -> IO Stringという定義の関数は
どういう値を返せばいいのかわかんない…。
っていうか、関数じゃない?アクションですか。
じゃあ、空のアクションということで…

import System

cat :: String -> IO ()
cat fn = do
  cs <- readFile(fn)
  putStr cs

cats :: [String] -> IO ()
cats [] = return ()
cats (x:xs) = do
  cat x
  cats xs

main = do
  args <- getArgs
  cats args

おお、動くよ、動く。
でも…なんだかなぁ、全然関数型プログラミングっぽくない。
doが非常に邪道な気がしてならない(関数型のなんたるかを知りもせずw)。

じゃ、そろそろ他の人のcat実装例を見てみる。

import System
main = do args <- getArgs
          case args of
            [] -> putStr =<< getContents
            _  -> mapM_ (\a -> putStr =<< readFile a)

map?ああ、mapね、map。そりゃいい。
\?ああ、lambdaじゃん、こんにちは。
さらに、

import System
main = getArgs >>= mapM readFile >>= mapM_ putStr

エレガントだ。笑うしかない。

くやしいので自分のコードの改良を進める。
>>=ってなんだ?え?もうモナドの森へ迷いこまなきゃいけないのか。
モナドの謎は最後にとっておこうと思ったのにぃ。

import System

cat fn = readFile(fn) >>= putStr
cats [] = return ()
cats (x:xs) = cat x >> cats xs

main = getArgs >>= cats

はぁ、多少すっきり?
そりゃね、mapとlambdaのほうが適してるのは分かる。
でもね、(x:xs)で再帰してみたかっただけで…
むしゃくしゃしてやった。今は反省している