HaskellでPLEAC(9章)

HaskellでPLEAC 9 章 ディレクトリ

ファイル操作とかディレクトリ操作はSystem.DirectorySystem.FilePath.Posixを探せばいい。

それからHakyllとかTemplate Haskellとかチェックし始めた。

Haskellで日付をあつかう

PLEACのレシピ9.1 タイムスタンプをHaskellで書いてみたんだけどちょっとめんどくさかった(Pythonも日付はめんどくさいけど)。

import System.Posix.Files
import System.Time
import System.Posix.Types
import System.Environment

getTimes :: FilePath -> IO (ClockTime, ClockTime)
getTimes fp =
    do stat <- getFileStatus fp
       return (toct (accessTime stat),
               toct (modificationTime stat))

toct :: EpochTime -> ClockTime
toct et = TOD (truncate (toRational et)) 0

main :: IO ()
main = do
  (file:_) <- getArgs
  (atime, mtime) <- getTimes file
  print atime
  print mtime

getFileStatus関数で時間の情報はEpochTime型が返ってくるので、これをClockTime型に変換する

type EpochTime = CTime

EpochTimeはCTimeの別名なんだけど、CTimeはRealのインスタンスなのでtoRationalで有理数に変換してtruncateを通してIntegerに。

これをClockTime型のデータコンストラクタであるTODに通す。

ClockTime型の出力は

Sun Jul 22 09:10:59 JST 2012

もう少し細かく制御したい場合にはtoCalendarTime関数でCalendarTIme型に変換して望みのフォーマットにすればいい。

RWHの20.4にきちんと書いてあった。

ProductName Real World Haskell―実戦で学ぶ関数型言語プログラミング
Bryan O'Sullivan
オライリージャパン / 3990円 ( 2009-10-26 )


MaybeのmplusはPerlのor(||)みたいなもんか

pleacの7.3を解いた

その後環境変数HOMEとLOGDIRを||で繋ぎたいなぁと思ったけど>>=は失敗を運ぶから使えないよなぁと思っていたらmplusがあったかと。

import Data.List.Split
import Control.Applicative
import Control.Monad
import Text.Regex
import System.Environment

getpwnam username = do
  passwds <- map (splitOn ":") <$> lines <$> readFile "/etc/passwd" 
  return (filter (\line -> (line!!0)==username) passwds)

main :: IO ()
main = do
  (path:_) <- getArgs
  case matchRegexAll (mkRegex "^~([^/]*)") path of
    Nothing -> putStrLn path
    Just (_,uhome,subdir,cs) -> 
        if length cs == 1 && length (cs!!0) /= 0
        then do
          dir <- getpwnam (cs!!0) 
          if (length dir) == 1 
          then putStrLn $ ((dir!!0)!!5) ++ subdir
          else putStrLn $ "Error: " ++ uhome ++ " not found"
        else do
          homedir <- lookup "HOME" <$> getEnvironment
          logdir <- lookup "LOGDIR" <$> getEnvironment
          case homedir `mplus` logdir of
            Just home -> putStrLn $ home ++ subdir
            Nothing -> putStrLn "Error: Env[HOME] not found"

これでHOMEが見つかればその後のLOGDIRは無視するし、見つからなければ評価される。

さらにliftM2で書きなおした

else do
   result <- liftM2 mplus (lookup "HOME" <$> getEnvironment) (lookup "LOGDIR" <$> getEnvironment)
   case result of
      Just home -> putStrLn $ home ++ subdir
      Nothing -> putStrLn "Error: Env[HOME] not found"

Haskellで例外を受け取る

IOの例外をキャッチしたくてはまった。

import System.Environment
import Control.Exception
import Prelude hiding (catch)
import System.Exit

main = do
  (file:_) <- getArgs
  catch (putStr =<< readFile file) $ \e -> return (e::SomeException) >> print ("Error on reading file: " ++ file)

-- main = do
--   (file:_) <- getArgs
--   catch (putStr =<< readFile file) $ \_ -> print ("Error on reading file: " ++ file)

例外の型を指定しないといけないらしい。

Monadiusのページを改めて読んでみたら、よく理解できたので調子に乗って色々調べていたらいつの間にかFRP方面に迷い込んでいた

ふとMonadiusを読んでみたら、昔はちんぷんかんぷんだったのがかなり理解できるようになったので、自分でも簡単なゲームでも書きたくなってsofを追いかけていたらいつの間にかfunctional reactive programmingの方面に迷い込んでいたらしい。

「Amazonポチッとボタン」もいつの間にか完了していた。

ProductName The Haskell School of Expression: Learning Functional Programming through Multimedia
Professor Paul Hudak
Cambridge University Press / 3963円 ( 2000-06 )


Node.jsにもreactive programmingありそうだよなと思って調べてみたら、Trigger と Stream ベースの Reactive スタイルについて考えるを見つけたのだけど面白そう。あとで追いかける。

そういえば、CTMCPでreactive programmingに触れてたような気がするんだけどなぁとパラパラめくってみたけど、見つけられなかった。

記憶がバグってたのかなぁ

Stateモナドから理解したほうがいいんじゃないかなーと思うんだけど

久しぶりに@ringtaroコミュニティfでもくもくしてきました。

僕はStateモナドを理解してから「MaybeとかEitherよりも先にStateモナドを理解したほうがいいんじゃないかなー」と思ったので、そんな感じのものを書いてみました。

スタックマシンつくってたはずなのにevalが途中でどっかにいっちゃったのでそこはそのうちなおす。

すごいHaskellは読んだほうがいいと思う。

ProductName すごいHaskellたのしく学ぼう!
Miran Lipovača
オーム社 / 2940円 ( 2012-05-23 )


圏論の基礎

自分にはここまで必要なのか?と葛藤している。

ProductName 圏論の基礎

丸善出版 / 4935円 ( 2012-07-17 )


fmapとliftMとliftそしてliftIO

liftIOって結局何のためにあるのかわからないので調べていたらliftとliftIOの違いがわかり易かった。

RWHによれば

  • fmap: 純粋な関数をファンクタのレベルに引き上げる
  • liftM: 純粋な関数をモナドのレベルに引き上げる
  • lift: モナドアクションを変換子層の一つ下のレベルから現在の層へあげる

liftIOはControl.Monad.IO.Class

class (Monad m) => MonadIO m where
    -- | Lift a computation from the 'IO' monad.
    liftIO :: IO a -> m a

参考

RWH3週目終了

ちょっと前からReal World Haskell 3周目を読んでいて、最近読み終わった。

読み始める前のポストイット(理解が曖昧なところに貼ってある)

1288005286

読後(かなり減った)

1342393758

すごいHaskellのおかげで理解がすすんだとことが結構あって、それをテコにしてRWHの内容がすんなり理解できたりしたのが大きかったかも。

ProductName すごいHaskellたのしく学ぼう!
Miran Lipovača
オーム社 / 2940円 ( 2012-05-23 )


Haskellで作っている人工無能に感情モデルを組み込んでみた

Haskellで人工無脳をつくろうというものを書いてます。

参考にしている書籍は「恋するプログラム―Rubyでつくる人工無脳」なんですけどね。

ProductName 恋するプログラム―Rubyでつくる人工無脳
秋山 智俊
毎日コミュニケーションズ / ?円 ( 2005-04 )


Rubyの書籍は楽しい本が多いんだけど、絶版することも多いですね。

Rubyで作る奇妙なプログラミング言語も絶版だしねー

ProductName Rubyで作る奇妙なプログラミング言語 ~Esoteric Language~
原 悠
毎日コミュニケーションズ / ?円 ( 2008-12-20 )


Pasec覚えるのに適当な言語のparser書くのも楽しいんだろうなーと思ったり、スタックを使った加減乗除を書いてみるのもよいだろうな。

PLEACの8章をHaskellで

PLEACのファイルコンテンツの章が面白そうだったのでHaskellでやってます

import System.IO
import System.Environment
import Control.Concurrent

main = do
  args <- getArgs
  h <- openFile (args!!0) ReadMode
  loop h
  where loop h = do 
          end <- hIsEOF h
          if end then (threadDelay 1000000) >> loop h
          else do
            c <- hGetChar h
            putChar c
            hFlush stdout
            loop h

sleepさせるのはSystem.PosixにもあったんだけどControl.ConcurrentのthreadDelayを使うほうがいいそうなんでそうしてみたけど理由はわからん。